Small refactoring on enumerating message schema element contents.
[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                         dc_importer.Import (schema_set_in_use);
82
83                         this.importer = importer;
84                         this.context = context;
85                         try {
86                                 DoImportContract ();
87                         } finally {
88                                 this.importer = null;
89                                 this.context = null;
90                         }
91                 }
92
93                 WsdlImporter importer;
94                 WsdlContractConversionContext context;
95
96                 XsdDataContractImporter dc_importer;
97
98                 XmlSchemaSet schema_set_in_use;
99
100                 void DoImportContract ()
101                 {
102                         PortType port_type = context.WsdlPortType;
103                         ContractDescription contract = context.Contract;
104                         int i, j;
105                         List<MessagePartDescription> parts = new List<MessagePartDescription> ();
106
107                         i = 0;
108                         foreach (Operation op in port_type.Operations) {
109                                 OperationDescription opdescr = contract.Operations [i];
110
111                                 j = 0;
112                                 foreach (OperationMessage opmsg in op.Messages) {
113                                         //SM.MessageDescription
114                                         MessageDescription msgdescr = opdescr.Messages [j];
115
116                                         //OpMsg's corresponding WSMessage
117                                         Message msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
118
119                                         msgdescr.Body.WrapperNamespace = port_type.ServiceDescription.TargetNamespace;
120
121                                         if (opmsg is OperationOutput) {
122                                                 //ReturnValue
123                                                 msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
124                                                 
125                                                 resolveMessage (msg, msgdescr.Body, parts);
126                                                 if (parts.Count > 0) {
127                                                         msgdescr.Body.ReturnValue = parts [0];
128                                                         parts.Clear ();
129                                                 }
130                                                 continue;
131                                         }
132
133                                         /* OperationInput */
134                                         
135                                         /* Parts, MessagePartDescription */
136                                         resolveMessage (msg, msgdescr.Body, parts);
137                                         foreach (MessagePartDescription p in parts)
138                                                 msgdescr.Body.Parts.Add (p);
139                                         parts.Clear ();
140
141                                         j ++;
142                                 }
143
144
145                                 i ++;
146                         }
147
148                 }
149
150                 void resolveMessage (Message msg, MessageBodyDescription body, List<MessagePartDescription> parts)
151                 {
152                         foreach (MessagePart part in msg.Parts) {
153                                 if (part.Name == "parameters") {
154                                         if (!part.Element.IsEmpty) {
155                                                 body.WrapperName = part.Element.Name;
156                                                 ImportPartsBySchemaElement (part.Element, parts, body.WrapperNamespace);
157                                         } else {
158                                                 body.WrapperName = part.Type.Name;
159                                                 resolveType (part.Type, parts, body.WrapperNamespace);
160                                         }
161                                 }
162                                 //FIXME: non-parameters?
163                         }
164                 }
165                 
166                 void ImportPartsBySchemaElement (QName qname, List<MessagePartDescription> parts, string ns)
167                 {
168                         XmlSchemaElement element = (XmlSchemaElement) schema_set_in_use.GlobalElements [qname];
169                         if (element == null)
170                                 //FIXME: What to do here?
171                                 throw new Exception ("Could not resolve : " + qname.ToString ());
172
173                         var ct = element.ElementSchemaType as XmlSchemaComplexType;
174                         if (ct == null) // simple type
175                                 parts.Add (CreateMessagePart (element));
176                         else // complex type
177                                 foreach (var elem in GetElementsInParticle (ct.ContentTypeParticle))
178                                         parts.Add (CreateMessagePart (elem));
179                 }
180
181                 IEnumerable<XmlSchemaElement> GetElementsInParticle (XmlSchemaParticle p)
182                 {
183                         if (p is XmlSchemaElement) {
184                                 yield return (XmlSchemaElement) p;
185                         } else {
186                                 var gb = p as XmlSchemaGroupBase;
187                                 if (gb != null)
188                                         foreach (XmlSchemaParticle pp in gb.Items)
189                                                 foreach (var e in GetElementsInParticle (pp))
190                                                         yield return e;
191                         }
192                 }
193
194                 MessagePartDescription CreateMessagePart (XmlSchemaElement elem)
195                 {
196                         var part = new MessagePartDescription (elem.QualifiedName.Name, elem.QualifiedName.Namespace);
197                         part.Importer = dc_importer;
198                         var typeQName = dc_importer.Import (schema_set_in_use, elem);
199                         part.CodeTypeReference = dc_importer.GetCodeTypeReference (typeQName);
200                         return part;
201                 }
202
203                 void resolveType (QName qname, List<MessagePartDescription> parts, string ns)
204                 {
205                         /*foreach (XmlSchema xs in importer.Schemas)
206                                 if (xs.Types [qname] != null)
207                                         return resolveParameters ((XmlSchemaElement) xs.Types [qname]., msgdescr, importer);
208
209                         //FIXME: What to do here?
210                         throw new Exception ("Could not resolve : " + qname.ToString ());*/
211                         throw new NotImplementedException ();
212                 }
213
214                 internal static string GetCLRTypeName (QName qname)
215                 {
216                         switch (qname.Namespace) {
217                         case "http://schemas.microsoft.com/2003/10/Serialization/":
218                                 if (qname.Name == "duration")
219                                         return "System.TimeSpan";
220                                 if (qname.Name == "guid")
221                                         return "System.Guid";
222                                 break;
223                         case "http://www.w3.org/2001/XMLSchema":
224                                 return GetCLRTypeName (qname.Name);
225                         }
226                         return null;
227                 }
228
229                 internal static string GetCLRTypeName (string xsdName)
230                 {
231                         switch (xsdName) {
232                         case "anyURI":
233                                 return "System.String";
234                         case "boolean":
235                                 return "System.Boolean";
236
237                         //FIXME: case "base64Binary":
238                         case "dateTime":
239                                 return "System.DateTime";
240                         case "QName":
241                                 return "System.String";
242                         case "decimal":
243                                 return "System.Decimal";
244                         case "double":
245                                 return "System.Double";
246                         case "float":
247                                 return "System.Double";
248                         case "byte":
249                                 return "System.SByte";
250                         case "short":
251                                 return "System.Int16";
252                         case "int":
253                                 return "System.Int32";
254                         case "long":
255                                 return "System.Int64";
256                         case "unsignedByte":
257                                 return "System.Byte";
258                         case "unsignedShort":
259                                 return "System.UInt16";
260                         case "unsignedInt":
261                                 return "System.UInt32";
262                         case "unsignedLong":
263                                 return "System.UInt64";
264                         case "string":
265                                 return "System.String";
266                         /* FIXME:
267                         case "anyType":
268                                 return true;
269                         default:
270                                 return false;*/
271                         }
272
273                         return null;
274                 }
275
276                 void IWsdlImportExtension.ImportEndpoint (WsdlImporter importer,
277                         WsdlEndpointConversionContext context)
278                 {
279                 }
280         }
281 }