fac5ba1ef391f6d9fbca0e11b6dcf087903e5c5b
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel.Description / DataContractSerializerMessageContractImporter.cs
1 //
2 // DataContractSerializerMessageContractImporter.cs
3 //
4 // Author: Atsushi Enomoto (atsushi@ximian.com)
5 //         Ankit Jain (jankit@novell.com)
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 using System;
29 using System.Collections.Generic;
30 using System.Collections.ObjectModel;
31 using System.Runtime.Serialization;
32 using System.ServiceModel;
33 using System.Text;
34 using System.Web.Services.Description;
35 using System.Xml;
36 using System.Xml.Schema;
37 using System.Xml.Serialization;
38
39 using QName = System.Xml.XmlQualifiedName;
40 using WSDL = System.Web.Services.Description.ServiceDescription;
41
42 namespace System.ServiceModel.Description
43 {
44         [MonoTODO]
45         public class DataContractSerializerMessageContractImporter
46                 : IWsdlImportExtension
47         {
48                 bool enabled = true;
49
50                 public bool Enabled {
51                         get { return enabled; }
52                         set { enabled = value; }
53                 }
54
55                 void IWsdlImportExtension.BeforeImport (
56                         ServiceDescriptionCollection wsdlDocuments,
57                         XmlSchemaSet xmlSchemas,
58                         ICollection<XmlElement> policy)
59                 {
60                 }
61
62                 void IWsdlImportExtension.ImportContract (WsdlImporter importer,
63                         WsdlContractConversionContext context)
64                 {
65                         if (!enabled)
66                                 return;
67
68                         if (importer == null)
69                                 throw new ArgumentNullException ("importer");
70                         if (context == null)
71                                 throw new ArgumentNullException ("context");
72                         if (this.importer != null || this.context != null)
73                                 throw new SystemException ("INTERNAL ERROR: unexpected recursion of ImportContract method call");
74
75                         dc_importer = new XsdDataContractImporter ();
76                         schema_set_in_use = new XmlSchemaSet ();
77                         schema_set_in_use.Add (importer.XmlSchemas);
78                         foreach (WSDL wsdl in importer.WsdlDocuments)
79                                 foreach (XmlSchema xs in wsdl.Types.Schemas)
80                                         schema_set_in_use.Add (xs);
81
82                         // commenting out this import operation, but might be required (I guess not).
83                         //dc_importer.Import (schema_set_in_use);
84                         schema_set_in_use.Compile ();
85
86                         this.importer = importer;
87                         this.context = context;
88                         try {
89                                 DoImportContract ();
90                         } finally {
91                                 this.importer = null;
92                                 this.context = null;
93                         }
94                 }
95
96                 WsdlImporter importer;
97                 WsdlContractConversionContext context;
98
99                 XsdDataContractImporter dc_importer;
100
101                 XmlSchemaSet schema_set_in_use;
102
103                 void DoImportContract ()
104                 {
105                         PortType port_type = context.WsdlPortType;
106                         ContractDescription contract = context.Contract;
107                         int i, j;
108                         List<MessagePartDescription> parts = new List<MessagePartDescription> ();
109
110                         i = 0;
111                         foreach (Operation op in port_type.Operations) {
112                                 OperationDescription opdescr = contract.Operations [i];
113
114                                 j = 0;
115                                 foreach (OperationMessage opmsg in op.Messages) {
116                                         //SM.MessageDescription
117                                         MessageDescription msgdescr = opdescr.Messages [j];
118
119                                         //OpMsg's corresponding WSMessage
120                                         Message msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
121
122                                         msgdescr.Body.WrapperNamespace = port_type.ServiceDescription.TargetNamespace;
123
124                                         if (opmsg is OperationOutput) {
125                                                 //ReturnValue
126                                                 msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
127                                                 
128                                                 resolveMessage (msg, msgdescr.Body, parts);
129                                                 if (parts.Count > 0) {
130                                                         msgdescr.Body.ReturnValue = parts [0];
131                                                         parts.Clear ();
132                                                 }
133                                                 continue;
134                                         }
135
136                                         /* OperationInput */
137                                         
138                                         /* Parts, MessagePartDescription */
139                                         resolveMessage (msg, msgdescr.Body, parts);
140                                         foreach (MessagePartDescription p in parts)
141                                                 msgdescr.Body.Parts.Add (p);
142                                         parts.Clear ();
143
144                                         j ++;
145                                 }
146
147
148                                 i ++;
149                         }
150
151                 }
152
153                 void resolveMessage (Message msg, MessageBodyDescription body, List<MessagePartDescription> parts)
154                 {
155                         foreach (MessagePart part in msg.Parts) {
156                                 if (part.Name == "parameters") {
157                                         if (!part.Element.IsEmpty) {
158                                                 body.WrapperName = part.Element.Name;
159                                                 ImportPartsBySchemaElement (part.Element, parts, body.WrapperNamespace);
160                                         } else {
161                                                 body.WrapperName = part.Type.Name;
162                                                 resolveType (part.Type, parts, body.WrapperNamespace);
163                                         }
164                                 }
165                                 //FIXME: non-parameters?
166                         }
167                 }
168                 
169                 void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, string ns)
170                 {
171                         XmlSchemaElement element = (XmlSchemaElement) schema_set_in_use.GlobalElements [qname];
172                         if (element == null)
173                                 //FIXME: What to do here?
174                                 throw new Exception ("Could not resolve : " + qname.ToString ());
175
176                         var ct = element.ElementSchemaType as XmlSchemaComplexType;
177                         if (ct == null) // simple type
178                                 parts.Add (CreateMessagePart (element));
179                         else // complex type
180                                 foreach (var elem in GetElementsInParticle (ct.ContentTypeParticle))
181                                         parts.Add (CreateMessagePart (elem));
182                 }
183
184                 IEnumerable<XmlSchemaElement> GetElementsInParticle (XmlSchemaParticle p)
185                 {
186                         if (p is XmlSchemaElement) {
187                                 yield return (XmlSchemaElement) p;
188                         } else {
189                                 var gb = p as XmlSchemaGroupBase;
190                                 if (gb != null)
191                                         foreach (XmlSchemaParticle pp in gb.Items)
192                                                 foreach (var e in GetElementsInParticle (pp))
193                                                         yield return e;
194                         }
195                 }
196
197                 MessagePartDescription CreateMessagePart (XmlSchemaElement elem)
198                 {
199                         var part = new MessagePartDescription (elem.QualifiedName.Name, elem.QualifiedName.Namespace);
200                         part.Importer = dc_importer;
201                         var typeQName = dc_importer.Import (schema_set_in_use, elem);
202                         part.CodeTypeReference = dc_importer.GetCodeTypeReference (typeQName);
203                         return part;
204                 }
205
206                 void resolveType (QName qname, List<MessagePartDescription> parts, string ns)
207                 {
208                         /*foreach (XmlSchema xs in importer.Schemas)
209                                 if (xs.Types [qname] != null)
210                                         return resolveParameters ((XmlSchemaElement) xs.Types [qname]., msgdescr, importer);
211
212                         //FIXME: What to do here?
213                         throw new Exception ("Could not resolve : " + qname.ToString ());*/
214                         throw new NotImplementedException ();
215                 }
216
217                 internal static string GetCLRTypeName (QName qname)
218                 {
219                         switch (qname.Namespace) {
220                         case "http://schemas.microsoft.com/2003/10/Serialization/":
221                                 if (qname.Name == "duration")
222                                         return "System.TimeSpan";
223                                 if (qname.Name == "guid")
224                                         return "System.Guid";
225                                 break;
226                         case "http://www.w3.org/2001/XMLSchema":
227                                 return GetCLRTypeName (qname.Name);
228                         }
229                         return null;
230                 }
231
232                 internal static string GetCLRTypeName (string xsdName)
233                 {
234                         switch (xsdName) {
235                         case "anyURI":
236                                 return "System.String";
237                         case "boolean":
238                                 return "System.Boolean";
239
240                         //FIXME: case "base64Binary":
241                         case "dateTime":
242                                 return "System.DateTime";
243                         case "QName":
244                                 return "System.String";
245                         case "decimal":
246                                 return "System.Decimal";
247                         case "double":
248                                 return "System.Double";
249                         case "float":
250                                 return "System.Double";
251                         case "byte":
252                                 return "System.SByte";
253                         case "short":
254                                 return "System.Int16";
255                         case "int":
256                                 return "System.Int32";
257                         case "long":
258                                 return "System.Int64";
259                         case "unsignedByte":
260                                 return "System.Byte";
261                         case "unsignedShort":
262                                 return "System.UInt16";
263                         case "unsignedInt":
264                                 return "System.UInt32";
265                         case "unsignedLong":
266                                 return "System.UInt64";
267                         case "string":
268                                 return "System.String";
269                         /* FIXME:
270                         case "anyType":
271                                 return true;
272                         default:
273                                 return false;*/
274                         }
275
276                         return null;
277                 }
278
279                 void IWsdlImportExtension.ImportEndpoint (WsdlImporter importer,
280                         WsdlEndpointConversionContext context)
281                 {
282                 }
283         }
284 }