* ConformanceChecker.cs, BasicProfileChecker.cs: New files that implement
[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
74                         string location = null;
75                         HttpAddressBinding sab = (HttpAddressBinding) Port.Extensions.Find (typeof(HttpAddressBinding));
76                         if (sab != null) location = sab.Location;
77                         string url = GetServiceUrl (location); 
78                         
79                         CodeConstructor cc = new CodeConstructor ();
80                         cc.Attributes = MemberAttributes.Public;
81                         CodeExpression ce = new CodeFieldReferenceExpression (new CodeThisReferenceExpression(), "Url");
82                         CodeAssignStatement cas = new CodeAssignStatement (ce, new CodePrimitiveExpression (url));
83                         cc.Statements.Add (cas);
84                         codeClass.Members.Add (cc);
85                         
86                         memberIds = new CodeIdentifiers ();
87                         return codeClass;
88                 }
89
90                 protected override void BeginNamespace ()
91                 {
92                         xmlImporter = new XmlSchemaImporter (LiteralSchemas, ClassNames);
93                         soapImporter = new SoapSchemaImporter (EncodedSchemas, ClassNames);
94                         xmlExporter = new XmlCodeExporter (CodeNamespace, null);
95                         xmlReflectionImporter = new XmlReflectionImporter ();
96                 }
97
98                 protected override void EndClass ()
99                 {
100                         if (xmlExporter.IncludeMetadata.Count > 0)
101                         {
102                                 if (CodeTypeDeclaration.CustomAttributes == null)
103                                         CodeTypeDeclaration.CustomAttributes = new CodeAttributeDeclarationCollection ();
104                                 CodeTypeDeclaration.CustomAttributes.AddRange (xmlExporter.IncludeMetadata);
105                         }
106                 }
107
108                 protected override void EndNamespace ()
109                 {
110                 }
111
112                 protected override bool IsBindingSupported ()
113                 {
114                         throw new NotImplementedException ();
115                 }
116
117                 [MonoTODO]
118                 protected override bool IsOperationFlowSupported (OperationFlow flow)
119                 {
120                         throw new NotImplementedException ();
121                 }
122
123                 protected override CodeMemberMethod GenerateMethod ()
124                 {
125                         try
126                         {
127                                 HttpOperationBinding httpOper = OperationBinding.Extensions.Find (typeof (HttpOperationBinding)) as HttpOperationBinding;
128                                 if (httpOper == null) throw new Exception ("Http operation binding not found");
129                                 
130                                 XmlMembersMapping inputMembers = ImportInMembersMapping (InputMessage);
131                                 XmlTypeMapping outputMember = ImportOutMembersMapping (OutputMessage);
132                                 
133                                 CodeMemberMethod met = GenerateMethod (memberIds, httpOper, inputMembers, outputMember);
134                                 
135                                 xmlExporter.ExportMembersMapping (inputMembers);
136                                 if (outputMember != null)
137                                         xmlExporter.ExportTypeMapping (outputMember);
138
139                                 return met;
140                         }
141                         catch (Exception ex)
142                         {
143                                 UnsupportedOperationBindingWarning (ex.Message);
144                                 return null;
145                         }
146                 }
147
148                 XmlMembersMapping ImportInMembersMapping (Message msg)
149                 {
150                         SoapSchemaMember[] mems = new SoapSchemaMember [msg.Parts.Count];
151                         for (int n=0; n<mems.Length; n++)
152                         {
153                                 SoapSchemaMember mem = new SoapSchemaMember();
154                                 mem.MemberName = msg.Parts[n].Name;
155                                 mem.MemberType = msg.Parts[n].Type;
156                                 mems[n] = mem;
157                         }
158                         return soapImporter.ImportMembersMapping (Operation.Name, "", mems);
159                 }
160                 
161                 XmlTypeMapping ImportOutMembersMapping (Message msg)
162                 {
163                         if (msg.Parts.Count == 0) return null;
164                         
165                         if (msg.Parts[0].Name == "Body" && msg.Parts[0].Element == XmlQualifiedName.Empty)
166                                 return xmlReflectionImporter.ImportTypeMapping (typeof(XmlNode));
167                         else
168                                 return xmlImporter.ImportTypeMapping (msg.Parts[0].Element);
169                 }
170                 
171                 CodeMemberMethod GenerateMethod (CodeIdentifiers memberIds, HttpOperationBinding httpOper, XmlMembersMapping inputMembers, XmlTypeMapping outputMember)
172                 {
173                         CodeIdentifiers pids = new CodeIdentifiers ();
174                         CodeMemberMethod method = new CodeMemberMethod ();
175                         CodeMemberMethod methodBegin = new CodeMemberMethod ();
176                         CodeMemberMethod methodEnd = new CodeMemberMethod ();
177                         method.Attributes = MemberAttributes.Public;
178                         methodBegin.Attributes = MemberAttributes.Public;
179                         methodEnd.Attributes = MemberAttributes.Public;
180                         
181                         // Find unique names for temporary variables
182                         
183                         for (int n=0; n<inputMembers.Count; n++)
184                                 pids.AddUnique (inputMembers[n].MemberName, inputMembers[n]);
185
186                         string varAsyncResult = pids.AddUnique ("asyncResult","asyncResult");
187                         string varResults = pids.AddUnique ("results","results");
188                         string varCallback = pids.AddUnique ("callback","callback");
189                         string varAsyncState = pids.AddUnique ("asyncState","asyncState");
190
191                         string messageName = memberIds.AddUnique(CodeIdentifier.MakeValid(Operation.Name),method);
192
193                         method.Name = Operation.Name;
194                         methodBegin.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("Begin" + Operation.Name),method);
195                         methodEnd.Name = memberIds.AddUnique(CodeIdentifier.MakeValid("End" + Operation.Name),method);
196
197                         method.ReturnType = new CodeTypeReference (typeof(void));
198                         methodEnd.ReturnType = new CodeTypeReference (typeof(void));
199                         methodEnd.Parameters.Add (new CodeParameterDeclarationExpression (typeof (IAsyncResult),varAsyncResult));
200
201                         CodeExpression[] paramArray = new CodeExpression [inputMembers.Count];
202
203                         for (int n=0; n<inputMembers.Count; n++)
204                         {
205                                 string ptype = GetSimpleType (inputMembers[n]);
206                                 CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression (ptype, inputMembers[n].MemberName);
207                                 
208                                 param.Direction = FieldDirection.In;
209                                 method.Parameters.Add (param);
210                                 methodBegin.Parameters.Add (param);
211                                 paramArray [n] = new CodeVariableReferenceExpression (param.Name);
212                         }
213
214                         bool isVoid = true;
215                         if (outputMember != null)
216                         {
217                                 method.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
218                                 methodEnd.ReturnType = new CodeTypeReference (outputMember.TypeFullName);
219                                 xmlExporter.AddMappingMetadata (method.ReturnTypeCustomAttributes, outputMember, "");
220                                 isVoid = false;
221                         }
222
223                         methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (AsyncCallback),varCallback));
224                         methodBegin.Parameters.Add (new CodeParameterDeclarationExpression (typeof (object),varAsyncState));
225                         methodBegin.ReturnType = new CodeTypeReference (typeof(IAsyncResult));
226
227                         // Array of input parameters
228                         
229                         CodeArrayCreateExpression methodParams;
230                         if (paramArray.Length > 0)
231                                 methodParams = new CodeArrayCreateExpression (typeof(object), paramArray);
232                         else
233                                 methodParams = new CodeArrayCreateExpression (typeof(object), 0);
234
235                         // Generate method url
236                         
237                         CodeThisReferenceExpression ethis = new CodeThisReferenceExpression();
238                         
239                         CodeExpression thisURlExp = new CodeFieldReferenceExpression (ethis, "Url");
240                         CodePrimitiveExpression metUrl = new CodePrimitiveExpression (httpOper.Location);
241                         CodeBinaryOperatorExpression expMethodLocation = new CodeBinaryOperatorExpression (thisURlExp, CodeBinaryOperatorType.Add, metUrl);
242                         
243                         // Invoke call
244                         
245                         CodePrimitiveExpression varMsgName = new CodePrimitiveExpression (messageName);
246                         CodeMethodInvokeExpression inv;
247
248                         inv = new CodeMethodInvokeExpression (ethis, "Invoke", varMsgName, expMethodLocation, methodParams);
249                         if (!isVoid)
250                                 method.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (method.ReturnType, inv)));
251                         else
252                                 method.Statements.Add (inv);
253                         
254                         // Begin Invoke Call
255                         
256                         CodeExpression expCallb = new CodeVariableReferenceExpression (varCallback);
257                         CodeExpression expAsyncs = new CodeVariableReferenceExpression (varAsyncState);
258                         inv = new CodeMethodInvokeExpression (ethis, "BeginInvoke", varMsgName, expMethodLocation, methodParams, expCallb, expAsyncs);
259                         methodBegin.Statements.Add (new CodeMethodReturnStatement (inv));
260                         
261                         // End Invoke call
262                         
263                         CodeExpression varAsyncr = new CodeVariableReferenceExpression (varAsyncResult);
264                         inv = new CodeMethodInvokeExpression (ethis, "EndInvoke", varAsyncr);
265                         if (!isVoid)
266                                 methodEnd.Statements.Add (new CodeMethodReturnStatement (new CodeCastExpression (methodEnd.ReturnType, inv)));
267                         else
268                                 methodEnd.Statements.Add (inv);
269                         
270                         // Attributes
271
272                         CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Web.Services.Protocols.HttpMethodAttribute");
273                         att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetOutMimeFormatter ())));
274                         att.Arguments.Add (new CodeAttributeArgument (new CodeTypeOfExpression(GetInMimeFormatter ())));
275                         AddCustomAttribute (method, att, true);
276                 
277                         CodeTypeDeclaration.Members.Add (method);
278                         CodeTypeDeclaration.Members.Add (methodBegin);
279                         CodeTypeDeclaration.Members.Add (methodEnd);
280                         
281                         return method;
282                 }               
283                 
284                 protected virtual Type GetInMimeFormatter ()
285                 {
286                         return null;
287                 }
288
289                 protected virtual Type GetOutMimeFormatter ()
290                 {
291                         if (OperationBinding.Output.Extensions.Find (typeof(MimeXmlBinding)) != null)
292                                 return typeof (XmlReturnReader);
293                                 
294                         MimeContentBinding bin = (MimeContentBinding) OperationBinding.Output.Extensions.Find (typeof(MimeContentBinding));
295                         if (bin != null && bin.Type == "text/xml")
296                                 return typeof (XmlReturnReader);
297                                 
298                         return typeof(NopReturnReader);
299                 }
300                 
301                 string GetSimpleType (XmlMemberMapping member)
302                 {
303                         // MS seems to always use System.String for input parameters, except for byte[]
304                         
305                         switch (member.TypeName)
306                         {
307                                 case "hexBinary":
308                                 case "base64Binary":
309                                         return "System.String";
310                                 
311                                 default:
312                                         string ptype = member.TypeFullName;
313                                         int i = ptype.IndexOf ('[');
314                                         if (i == -1)
315                                                 return "System.String";
316                                         else 
317                                                 return "System.String" + ptype.Substring (i);
318                         }
319                 }
320
321                 #endregion
322         }
323 }