**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Web.Services / System.Web.Services.Description / HttpSimpleProtocolImporter.cs
blob86a0f63cc584ee3423cbceb5a751c5a699e79222
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 //
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.
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;
40 namespace System.Web.Services.Description
42 internal abstract class HttpSimpleProtocolImporter : ProtocolImporter
45 #region Fields
47 HttpBinding httpBinding;
49 SoapCodeExporter soapExporter;
50 SoapSchemaImporter soapImporter;
51 XmlCodeExporter xmlExporter;
52 XmlSchemaImporter xmlImporter;
53 CodeIdentifiers memberIds;
54 XmlReflectionImporter xmlReflectionImporter;
56 #endregion // Fields
58 #region Constructors
60 public HttpSimpleProtocolImporter ()
64 #endregion // Constructors
66 #region Methods
68 protected override CodeTypeDeclaration BeginClass ()
70 httpBinding = (HttpBinding) Binding.Extensions.Find (typeof(HttpBinding));
72 CodeTypeDeclaration codeClass = new CodeTypeDeclaration (ClassName);
74 string location = null;
75 if (Port != null) {
76 HttpAddressBinding sab = (HttpAddressBinding) Port.Extensions.Find (typeof(HttpAddressBinding));
77 if (sab != null) location = sab.Location;
80 CodeConstructor cc = new CodeConstructor ();
81 cc.Attributes = MemberAttributes.Public;
82 GenerateServiceUrl (location, cc.Statements);
83 codeClass.Members.Add (cc);
85 memberIds = new CodeIdentifiers ();
86 return codeClass;
89 protected override void BeginNamespace ()
91 xmlImporter = new XmlSchemaImporter (LiteralSchemas, ClassNames);
92 soapImporter = new SoapSchemaImporter (EncodedSchemas, ClassNames);
93 xmlExporter = new XmlCodeExporter (CodeNamespace, null);
94 xmlReflectionImporter = new XmlReflectionImporter ();
97 protected override void EndClass ()
99 if (xmlExporter.IncludeMetadata.Count > 0)
101 if (CodeTypeDeclaration.CustomAttributes == null)
102 CodeTypeDeclaration.CustomAttributes = new CodeAttributeDeclarationCollection ();
103 CodeTypeDeclaration.CustomAttributes.AddRange (xmlExporter.IncludeMetadata);
107 protected override void EndNamespace ()
111 protected override bool IsBindingSupported ()
113 throw new NotImplementedException ();
116 [MonoTODO]
117 protected override bool IsOperationFlowSupported (OperationFlow flow)
119 throw new NotImplementedException ();
122 protected override CodeMemberMethod GenerateMethod ()
126 HttpOperationBinding httpOper = OperationBinding.Extensions.Find (typeof (HttpOperationBinding)) as HttpOperationBinding;
127 if (httpOper == null) throw new Exception ("Http operation binding not found");
129 XmlMembersMapping inputMembers = ImportInMembersMapping (InputMessage);
130 XmlTypeMapping outputMember = ImportOutMembersMapping (OutputMessage);
132 CodeMemberMethod met = GenerateMethod (memberIds, httpOper, inputMembers, outputMember);
134 xmlExporter.ExportMembersMapping (inputMembers);
135 if (outputMember != null)
136 xmlExporter.ExportTypeMapping (outputMember);
138 return met;
140 catch (Exception ex)
142 UnsupportedOperationBindingWarning (ex.Message);
143 return null;
147 XmlMembersMapping ImportInMembersMapping (Message msg)
149 SoapSchemaMember[] mems = new SoapSchemaMember [msg.Parts.Count];
150 for (int n=0; n<mems.Length; n++)
152 SoapSchemaMember mem = new SoapSchemaMember();
153 mem.MemberName = msg.Parts[n].Name;
154 mem.MemberType = msg.Parts[n].Type;
155 mems[n] = mem;
157 return soapImporter.ImportMembersMapping (Operation.Name, "", mems);
160 XmlTypeMapping ImportOutMembersMapping (Message msg)
162 if (msg.Parts.Count == 0) return null;
164 if (msg.Parts[0].Name == "Body" && msg.Parts[0].Element == XmlQualifiedName.Empty)
165 return xmlReflectionImporter.ImportTypeMapping (typeof(XmlNode));
166 else {
167 // This is a bit hacky. The issue is that types such as string[] are to be imported
168 // as such, not as ArrayOfString class. ImportTypeMapping will return a
169 // class if the type has not been imported as an array before, hence the
170 // call to ImportMembersMapping.
171 xmlImporter.ImportMembersMapping (new XmlQualifiedName[] {msg.Parts[0].Element});
172 return xmlImporter.ImportTypeMapping (msg.Parts[0].Element);
176 CodeMemberMethod GenerateMethod (CodeIdentifiers memberIds, HttpOperationBinding httpOper, XmlMembersMapping inputMembers, XmlTypeMapping outputMember)
178 CodeIdentifiers pids = new CodeIdentifiers ();
179 CodeMemberMethod method = new CodeMemberMethod ();
180 CodeMemberMethod methodBegin = new CodeMemberMethod ();
181 CodeMemberMethod methodEnd = new CodeMemberMethod ();
182 method.Attributes = MemberAttributes.Public;
183 methodBegin.Attributes = MemberAttributes.Public;
184 methodEnd.Attributes = MemberAttributes.Public;
186 // Find unique names for temporary variables
188 for (int n=0; n<inputMembers.Count; n++)
189 pids.AddUnique (inputMembers[n].MemberName, inputMembers[n]);
191 string varAsyncResult = pids.AddUnique ("asyncResult","asyncResult");
192 string varResults = pids.AddUnique ("results","results");
193 string varCallback = pids.AddUnique ("callback","callback");
194 string varAsyncState = pids.AddUnique ("asyncState","asyncState");
196 string messageName = memberIds.AddUnique(CodeIdentifier.MakeValid(Operation.Name),method);
198 method.Name = Operation.Name;
199 methodBegin.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("Begin" + Operation.Name),method);
200 methodEnd.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("End" + Operation.Name),method);
202 method.ReturnType = new CodeTypeReference (typeof(void));
203 methodEnd.ReturnType = new CodeTypeReference (typeof(void));
204 methodEnd.Parameters.Add (new CodeParameterDeclarationExpression (typeof (IAsyncResult),varAsyncResult));
206 CodeExpression[] paramArray = new CodeExpression [inputMembers.Count];
208 for (int n=0; n<inputMembers.Count; n++)
210 string ptype = GetSimpleType (inputMembers[n]);
211 CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression (ptype, inputMembers[n].MemberName);
213 param.Direction = FieldDirection.In;
214 method.Parameters.Add (param);
215 methodBegin.Parameters.Add (param);
216 paramArray [n] = new CodeVariableReferenceExpression (param.Name);
219 bool isVoid = true;
220 if (outputMember != null)
222 method.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
223 methodEnd.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
224 xmlExporter.AddMappingMetadata (method.ReturnTypeCustomAttributes, outputMember, "");
225 isVoid = false;
228 methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (AsyncCallback),varCallback));
229 methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object),varAsyncState));
230 methodBegin.ReturnType = new CodeTypeReference (typeof(IAsyncResult));
232 // Array of input parameters
234 CodeArrayCreateExpression methodParams;
235 if (paramArray.Length > 0)
236 methodParams = new CodeArrayCreateExpression (typeof(object), paramArray);
237 else
238 methodParams = new CodeArrayCreateExpression (typeof(object), 0);
240 // Generate method url
242 CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
244 CodeExpression thisURlExp = new CodeFieldReferenceExpression (ethis, "Url");
245 CodePrimitiveExpression metUrl = new CodePrimitiveExpression (httpOper.Location);
246 CodeBinaryOperatorExpression expMethodLocation = new CodeBinaryOperatorExpression (thisURlExp, CodeBinaryOperatorType.Add, metUrl);
248 // Invoke call
250 CodePrimitiveExpression varMsgName = new CodePrimitiveExpression (messageName);
251 CodeMethodInvokeExpression inv;
253 inv = new CodeMethodInvokeExpression (ethis, "Invoke", varMsgName, expMethodLocation, methodParams);
254 if (!isVoid)
255 method.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (method.ReturnType, inv)));
256 else
257 method.Statements.Add (inv);
259 // Begin Invoke Call
261 CodeExpression expCallb = new CodeVariableReferenceExpression (varCallback);
262 CodeExpression expAsyncs = new CodeVariableReferenceExpression (varAsyncState);
263 inv = new CodeMethodInvokeExpression (ethis, "BeginInvoke", varMsgName, expMethodLocation, methodParams, expCallb, expAsyncs);
264 methodBegin.Statements.Add (new CodeMethodReturnStatement (inv));
266 // End Invoke call
268 CodeExpression varAsyncr = new CodeVariableReferenceExpression (varAsyncResult);
269 inv = new CodeMethodInvokeExpression (ethis, "EndInvoke", varAsyncr);
270 if (!isVoid)
271 methodEnd.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (methodEnd.ReturnType, inv)));
272 else
273 methodEnd.Statements.Add (inv);
275 // Attributes
277 CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.HttpMethodAttribute");
278 att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetOutMimeFormatter ())));
279 att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetInMimeFormatter ())));
280 AddCustomAttribute (method, att, true);
282 CodeTypeDeclaration.Members.Add (method);
283 CodeTypeDeclaration.Members.Add (methodBegin);
284 CodeTypeDeclaration.Members.Add (methodEnd);
286 return method;
289 #if NET_2_0
290 internal override CodeExpression BuildInvokeAsync (string messageName, CodeArrayCreateExpression paramsArray, CodeExpression delegateField, CodeExpression userStateVar)
292 HttpOperationBinding httpOper = OperationBinding.Extensions.Find (typeof (HttpOperationBinding)) as HttpOperationBinding;
294 CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
296 CodeExpression thisURlExp = new CodeFieldReferenceExpression (ethis, "Url");
297 CodePrimitiveExpression metUrl = new CodePrimitiveExpression (httpOper.Location);
298 CodeBinaryOperatorExpression expMethodLocation = new CodeBinaryOperatorExpression (thisURlExp, CodeBinaryOperatorType.Add, metUrl);
300 CodeMethodInvokeExpression inv2 = new CodeMethodInvokeExpression (ethis, "InvokeAsync");
301 inv2.Parameters.Add (new CodePrimitiveExpression (messageName));
302 inv2.Parameters.Add (expMethodLocation);
303 inv2.Parameters.Add (paramsArray);
304 inv2.Parameters.Add (delegateField);
305 inv2.Parameters.Add (userStateVar);
306 return inv2;
308 #endif
310 protected virtual Type GetInMimeFormatter ()
312 return null;
315 protected virtual Type GetOutMimeFormatter ()
317 if (OperationBinding.Output.Extensions.Find (typeof(MimeXmlBinding)) != null)
318 return typeof (XmlReturnReader);
320 MimeContentBinding bin = (MimeContentBinding) OperationBinding.Output.Extensions.Find (typeof(MimeContentBinding));
321 if (bin != null && bin.Type == "text/xml")
322 return typeof (XmlReturnReader);
324 return typeof(NopReturnReader);
327 string GetSimpleType (XmlMemberMapping member)
329 // MS seems to always use System.String for input parameters, except for byte[]
331 switch (member.TypeName)
333 case "hexBinary":
334 case "base64Binary":
335 return "System.String";
337 default:
338 string ptype = member.TypeFullName;
339 int i = ptype.IndexOf ('[');
340 if (i == -1)
341 return "System.String";
342 else
343 return "System.String" + ptype.Substring (i);
347 #endregion