[threadpool] Added dynamic concurrent queue implementation
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / HttpSimpleProtocolImporter.cs
1 // 
2 // System.Web.Services.Description.HttpSimpleProtocolImporter.cs
3 //
4 // Author:
5 //   Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // Copyright (C) 2003 Ximian, Inc.
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.CodeDom;
32 using System.Web.Services;
33 using System.Web.Services.Protocols;
34 using System.Web.Services.Configuration;
35 using System.Xml;
36 using System.Xml.Serialization;
37 using System.Configuration;
38 using System.Collections;
39
40 namespace System.Web.Services.Description 
41 {
42         internal abstract class HttpSimpleProtocolImporter : ProtocolImporter 
43         {
44
45                 #region Fields
46
47                 HttpBinding httpBinding;
48                 
49                 SoapCodeExporter soapExporter;
50                 SoapSchemaImporter soapImporter;
51                 XmlCodeExporter xmlExporter;
52                 XmlSchemaImporter xmlImporter;
53                 CodeIdentifiers memberIds;
54                 XmlReflectionImporter xmlReflectionImporter;
55                 
56                 #endregion // Fields
57
58                 #region Constructors
59
60                 public HttpSimpleProtocolImporter ()
61                 {
62                 }
63                 
64                 #endregion // Constructors
65
66                 #region Methods
67
68                 protected override CodeTypeDeclaration BeginClass ()
69                 {
70                         httpBinding = (HttpBinding) Binding.Extensions.Find (typeof(HttpBinding));
71
72                         CodeTypeDeclaration codeClass = new CodeTypeDeclaration (ClassName);
73 #if NET_2_0
74                         codeClass.IsPartial = true;
75 #endif
76
77                         string location = null;
78                         if (Port != null) {
79                                 HttpAddressBinding sab = (HttpAddressBinding) Port.Extensions.Find (typeof(HttpAddressBinding));
80                                 if (sab != null) location = sab.Location;
81                         }
82                         
83                         CodeConstructor cc = new CodeConstructor ();
84                         cc.Attributes = MemberAttributes.Public;
85                         GenerateServiceUrl (location, cc.Statements);
86                         codeClass.Members.Add (cc);
87                         
88                         memberIds = new CodeIdentifiers ();
89                         return codeClass;
90                 }
91
92                 protected override void BeginNamespace ()
93                 {
94                         xmlImporter = new XmlSchemaImporter (LiteralSchemas, ClassNames);
95                         soapImporter = new SoapSchemaImporter (EncodedSchemas, ClassNames);
96                         xmlExporter = new XmlCodeExporter (CodeNamespace, null);
97                         xmlReflectionImporter = new XmlReflectionImporter ();
98                 }
99
100                 protected override void EndClass ()
101                 {
102                         if (xmlExporter.IncludeMetadata.Count > 0)
103                         {
104                                 if (CodeTypeDeclaration.CustomAttributes == null)
105                                         CodeTypeDeclaration.CustomAttributes = new CodeAttributeDeclarationCollection ();
106                                 CodeTypeDeclaration.CustomAttributes.AddRange (xmlExporter.IncludeMetadata);
107                         }
108                 }
109
110                 protected override void EndNamespace ()
111                 {
112                 }
113
114                 protected override bool IsBindingSupported ()
115                 {
116                         throw new NotImplementedException ();
117                 }
118
119                 [MonoTODO]
120                 protected override bool IsOperationFlowSupported (OperationFlow flow)
121                 {
122                         throw new NotImplementedException ();
123                 }
124
125                 protected override CodeMemberMethod GenerateMethod ()
126                 {
127                         try
128                         {
129                                 HttpOperationBinding httpOper = OperationBinding.Extensions.Find (typeof (HttpOperationBinding)) as HttpOperationBinding;
130                                 if (httpOper == null) throw new Exception ("Http operation binding not found");
131                                 
132                                 XmlMembersMapping inputMembers = ImportInMembersMapping (InputMessage);
133                                 XmlTypeMapping outputMember = ImportOutMembersMapping (OutputMessage);
134                                 
135                                 CodeMemberMethod met = GenerateMethod (memberIds, httpOper, inputMembers, outputMember);
136                                 
137                                 xmlExporter.ExportMembersMapping (inputMembers);
138                                 if (outputMember != null)
139                                         xmlExporter.ExportTypeMapping (outputMember);
140
141                                 return met;
142                         }
143                         catch (Exception ex)
144                         {
145                                 UnsupportedOperationBindingWarning (ex.Message);
146                                 return null;
147                         }
148                 }
149
150                 XmlMembersMapping ImportInMembersMapping (Message msg)
151                 {
152                         SoapSchemaMember[] mems = new SoapSchemaMember [msg.Parts.Count];
153                         for (int n=0; n<mems.Length; n++)
154                         {
155                                 SoapSchemaMember mem = new SoapSchemaMember();
156                                 mem.MemberName = msg.Parts[n].Name;
157                                 mem.MemberType = msg.Parts[n].Type;
158                                 mems[n] = mem;
159                         }
160                         return soapImporter.ImportMembersMapping (Operation.Name, "", mems);
161                 }
162                 
163                 XmlTypeMapping ImportOutMembersMapping (Message msg)
164                 {
165                         if (msg.Parts.Count == 0) return null;
166                         
167                         if (msg.Parts[0].Name == "Body" && msg.Parts[0].Element == XmlQualifiedName.Empty)
168                                 return xmlReflectionImporter.ImportTypeMapping (typeof(XmlNode));
169                         else {
170                                 // This is a bit hacky. The issue is that types such as string[] are to be imported
171                                 // as such, not as ArrayOfString class. ImportTypeMapping will return a
172                                 // class if the type has not been imported as an array before, hence the
173                                 // call to ImportMembersMapping.
174                                 xmlImporter.ImportMembersMapping (new XmlQualifiedName[] {msg.Parts[0].Element});
175                                 return xmlImporter.ImportTypeMapping (msg.Parts[0].Element);
176                         }
177                 }
178                 
179                 CodeMemberMethod GenerateMethod (CodeIdentifiers memberIds, HttpOperationBinding httpOper, XmlMembersMapping inputMembers, XmlTypeMapping outputMember)
180                 {
181                         CodeIdentifiers pids = new CodeIdentifiers ();
182                         CodeMemberMethod method = new CodeMemberMethod ();
183                         CodeMemberMethod methodBegin = new CodeMemberMethod ();
184                         CodeMemberMethod methodEnd = new CodeMemberMethod ();
185                         method.Attributes = MemberAttributes.Public;
186                         methodBegin.Attributes = MemberAttributes.Public;
187                         methodEnd.Attributes = MemberAttributes.Public;
188                         
189                         // Find unique names for temporary variables
190                         
191                         for (int n=0; n<inputMembers.Count; n++)
192                                 pids.AddUnique (inputMembers[n].MemberName, inputMembers[n]);
193
194                         string varAsyncResult = pids.AddUnique ("asyncResult","asyncResult");
195                         string varCallback = pids.AddUnique ("callback","callback");
196                         string varAsyncState = pids.AddUnique ("asyncState","asyncState");
197
198                         string messageName = memberIds.AddUnique(CodeIdentifier.MakeValid(Operation.Name),method);
199
200                         method.Name = Operation.Name;
201                         methodBegin.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("Begin" + Operation.Name),method);
202                         methodEnd.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("End" + Operation.Name),method);
203
204                         method.ReturnType = new CodeTypeReference (typeof(void));
205                         methodEnd.ReturnType = new CodeTypeReference (typeof(void));
206                         methodEnd.Parameters.Add (new CodeParameterDeclarationExpression (typeof (IAsyncResult),varAsyncResult));
207
208                         CodeExpression[] paramArray = new CodeExpression [inputMembers.Count];
209
210                         for (int n=0; n<inputMembers.Count; n++)
211                         {
212                                 string ptype = GetSimpleType (inputMembers[n]);
213                                 CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression (ptype, inputMembers[n].MemberName);
214                                 
215                                 param.Direction = FieldDirection.In;
216                                 method.Parameters.Add (param);
217                                 methodBegin.Parameters.Add (param);
218                                 paramArray [n] = new CodeVariableReferenceExpression (param.Name);
219                         }
220
221                         bool isVoid = true;
222                         if (outputMember != null)
223                         {
224                                 method.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
225                                 methodEnd.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
226                                 xmlExporter.AddMappingMetadata (method.ReturnTypeCustomAttributes, outputMember, "");
227                                 isVoid = false;
228                         }
229
230                         methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (AsyncCallback),varCallback));
231                         methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object),varAsyncState));
232                         methodBegin.ReturnType = new CodeTypeReference (typeof(IAsyncResult));
233
234                         // Array of input parameters
235                         
236                         CodeArrayCreateExpression methodParams;
237                         if (paramArray.Length > 0)
238                                 methodParams = new CodeArrayCreateExpression (typeof(object), paramArray);
239                         else
240                                 methodParams = new CodeArrayCreateExpression (typeof(object), 0);
241
242                         // Generate method url
243                         
244                         CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
245                         
246                         CodeExpression thisURlExp = new CodeFieldReferenceExpression (ethis, "Url");
247                         CodePrimitiveExpression metUrl = new CodePrimitiveExpression (httpOper.Location);
248                         CodeBinaryOperatorExpression expMethodLocation = new CodeBinaryOperatorExpression (thisURlExp, CodeBinaryOperatorType.Add, metUrl);
249                         
250                         // Invoke call
251                         
252                         CodePrimitiveExpression varMsgName = new CodePrimitiveExpression (messageName);
253                         CodeMethodInvokeExpression inv;
254
255                         inv = new CodeMethodInvokeExpression (ethis, "Invoke", varMsgName, expMethodLocation, methodParams);
256                         if (!isVoid)
257                                 method.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (method.ReturnType, inv)));
258                         else
259                                 method.Statements.Add (inv);
260                         
261                         // Begin Invoke Call
262                         
263                         CodeExpression expCallb = new CodeVariableReferenceExpression (varCallback);
264                         CodeExpression expAsyncs = new CodeVariableReferenceExpression (varAsyncState);
265                         inv = new CodeMethodInvokeExpression (ethis, "BeginInvoke", varMsgName, expMethodLocation, methodParams, expCallb, expAsyncs);
266                         methodBegin.Statements.Add (new CodeMethodReturnStatement (inv));
267                         
268                         // End Invoke call
269                         
270                         CodeExpression varAsyncr = new CodeVariableReferenceExpression (varAsyncResult);
271                         inv = new CodeMethodInvokeExpression (ethis, "EndInvoke", varAsyncr);
272                         if (!isVoid)
273                                 methodEnd.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (methodEnd.ReturnType, inv)));
274                         else
275                                 methodEnd.Statements.Add (inv);
276                         
277                         // Attributes
278
279                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.HttpMethodAttribute");
280                         att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetOutMimeFormatter ())));
281                         att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetInMimeFormatter ())));
282                         AddCustomAttribute (method, att, true);
283                 
284                         CodeTypeDeclaration.Members.Add (method);
285                         CodeTypeDeclaration.Members.Add (methodBegin);
286                         CodeTypeDeclaration.Members.Add (methodEnd);
287                         
288                         return method;
289                 }               
290
291 #if NET_2_0
292                 internal override CodeExpression BuildInvokeAsync (string messageName, CodeArrayCreateExpression paramsArray, CodeExpression delegateField, CodeExpression userStateVar)
293                 {
294                         HttpOperationBinding httpOper = OperationBinding.Extensions.Find (typeof (HttpOperationBinding)) as HttpOperationBinding;
295                         
296                         CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
297                         
298                         CodeExpression thisURlExp = new CodeFieldReferenceExpression (ethis, "Url");
299                         CodePrimitiveExpression metUrl = new CodePrimitiveExpression (httpOper.Location);
300                         CodeBinaryOperatorExpression expMethodLocation = new CodeBinaryOperatorExpression (thisURlExp, CodeBinaryOperatorType.Add, metUrl);
301                         
302                         CodeMethodInvokeExpression inv2 = new CodeMethodInvokeExpression (ethis, "InvokeAsync");
303                         inv2.Parameters.Add (new CodePrimitiveExpression (messageName));
304                         inv2.Parameters.Add (expMethodLocation);
305                         inv2.Parameters.Add (paramsArray);
306                         inv2.Parameters.Add (delegateField);
307                         inv2.Parameters.Add (userStateVar);
308                         return inv2;
309                 }
310 #endif
311                 
312                 protected virtual Type GetInMimeFormatter ()
313                 {
314                         return null;
315                 }
316
317                 protected virtual Type GetOutMimeFormatter ()
318                 {
319                         if (OperationBinding.Output.Extensions.Find (typeof(MimeXmlBinding)) != null)
320                                 return typeof (XmlReturnReader);
321                                 
322                         MimeContentBinding bin = (MimeContentBinding) OperationBinding.Output.Extensions.Find (typeof(MimeContentBinding));
323                         if (bin != null && bin.Type == "text/xml")
324                                 return typeof (XmlReturnReader);
325                                 
326                         return typeof(NopReturnReader);
327                 }
328                 
329                 string GetSimpleType (XmlMemberMapping member)
330                 {
331                         // MS seems to always use System.String for input parameters, except for byte[]
332                         
333                         switch (member.TypeName)
334                         {
335                                 case "hexBinary":
336                                 case "base64Binary":
337                                         return "System.String";
338                                 
339                                 default:
340                                         string ptype = member.TypeFullName;
341                                         int i = ptype.IndexOf ('[');
342                                         if (i == -1)
343                                                 return "System.String";
344                                         else 
345                                                 return "System.String" + ptype.Substring (i);
346                         }
347                 }
348
349                 #endregion
350         }
351 }