New test.
[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.ServiceModel;
32 using System.Text;
33 using System.Web.Services.Description;
34 using System.Xml;
35 using System.Xml.Schema;
36 using System.Xml.Serialization;
37
38 using QName = System.Xml.XmlQualifiedName;
39 using WSDL = System.Web.Services.Description.ServiceDescription;
40
41 namespace System.ServiceModel.Description
42 {
43         [MonoTODO]
44         public class DataContractSerializerMessageContractImporter
45                 : IWsdlImportExtension
46         {
47                 bool enabled = true;
48
49                 public bool Enabled {
50                         get { return enabled; }
51                         set { enabled = value; }
52                 }
53
54                 void IWsdlImportExtension.BeforeImport (
55                         ServiceDescriptionCollection wsdlDocuments,
56                         XmlSchemaSet xmlSchemas,
57                         ICollection<XmlElement> policy)
58                 {
59                 }
60
61                 void IWsdlImportExtension.ImportContract (WsdlImporter importer,
62                         WsdlContractConversionContext context)
63                 {
64                         if (!enabled)
65                                 return;
66
67                         if (importer == null)
68                                 throw new ArgumentNullException ("importer");
69                         if (context == null)
70                                 throw new ArgumentNullException ("context");
71                         if (this.importer != null || this.context != null)
72                                 throw new SystemException ("INTERNAL ERROR: unexpected recursion of ImportContract method call");
73
74                         this.importer = importer;
75                         this.context = context;
76                         try {
77                                 DoImportContract ();
78                         } finally {
79                                 this.importer = null;
80                                 this.context = null;
81                         }
82                 }
83
84                 WsdlImporter importer;
85                 WsdlContractConversionContext context;
86                 XmlSchemaImporter schema_importer_;
87                 XmlSchemaImporter schema_importer {
88                         get {
89                                 if (schema_importer_ != null)
90                                         return schema_importer_;
91                                 schema_importer_ = new XmlSchemaImporter (xml_schemas);
92                                 return schema_importer_;
93                         }
94                 }
95
96                 XmlSchemas xml_schemas_;
97                 XmlSchemas xml_schemas {
98                         get {
99                                 if (xml_schemas_ != null)
100                                         return xml_schemas_;
101                                 xml_schemas_ = new XmlSchemas ();
102
103                                 foreach (WSDL wsdl in importer.WsdlDocuments)
104                                         foreach (XmlSchema schema in wsdl.Types.Schemas)
105                                                 xml_schemas_.Add (schema);
106
107                                 foreach (XmlSchema schema in importer.XmlSchemas.Schemas ())
108                                         xml_schemas_.Add (schema);
109
110                                 xml_schemas_.Compile (null, true);
111
112                                 return xml_schemas_;
113                         }
114                 }
115
116                 void DoImportContract ()
117                 {
118                         PortType port_type = context.WsdlPortType;
119                         ContractDescription contract = context.Contract;
120                         int i, j;
121                         List<MessagePartDescription> parts = new List<MessagePartDescription> ();
122
123                         i = 0;
124                         foreach (Operation op in port_type.Operations) {
125                                 OperationDescription opdescr = contract.Operations [i];
126
127                                 j = 0;
128                                 foreach (OperationMessage opmsg in op.Messages) {
129                                         //SM.MessageDescription
130                                         MessageDescription msgdescr = opdescr.Messages [j];
131
132                                         //OpMsg's corresponding WSMessage
133                                         Message msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
134
135                                         msgdescr.Body.WrapperNamespace = port_type.ServiceDescription.TargetNamespace;
136
137                                         if (opmsg is OperationOutput) {
138                                                 //ReturnValue
139                                                 msg = port_type.ServiceDescription.Messages [opmsg.Message.Name];
140                                                 
141                                                 resolveMessage (msg, msgdescr.Body, parts);
142                                                 if (parts.Count > 0) {
143                                                         msgdescr.Body.ReturnValue = parts [0];
144                                                         parts.Clear ();
145                                                 }
146                                                 continue;
147                                         }
148
149                                         /* OperationInput */
150                                         
151                                         /* Parts, MessagePartDescription */
152                                         resolveMessage (msg, msgdescr.Body, parts);
153                                         foreach (MessagePartDescription p in parts)
154                                                 msgdescr.Body.Parts.Add (p);
155                                         parts.Clear ();
156
157                                         j ++;
158                                 }
159
160
161                                 i ++;
162                         }
163
164                 }
165
166                 void resolveMessage (Message msg, MessageBodyDescription body, List<MessagePartDescription> parts)
167                 {
168                         foreach (MessagePart part in msg.Parts) {
169                                 if (part.Name == "parameters") {
170                                         if (!part.Element.IsEmpty) {
171                                                 body.WrapperName = part.Element.Name;
172                                                 resolveElement (part.Element, parts, body.WrapperNamespace);
173                                         } else {
174                                                 body.WrapperName = part.Type.Name;
175                                                 resolveType (part.Type, parts, body.WrapperNamespace);
176                                         }
177                                 }
178                                 //FIXME: non-parameters?
179                         }
180                 }
181                 
182                 void resolveElement (QName qname, List<MessagePartDescription> parts, string ns)
183                 {
184                         XmlSchemaElement element = (XmlSchemaElement) xml_schemas.Find (qname, typeof (XmlSchemaElement));
185                         if (element == null)
186                                 //FIXME: What to do here?
187                                 throw new Exception ("Could not resolve : " + qname.ToString ());
188
189                         resolveParticle (schema_importer, element, parts, ns, 2);
190                 }
191
192                 void resolveType (QName qname, List<MessagePartDescription> parts, string ns)
193                 {
194                         /*foreach (XmlSchema xs in importer.Schemas)
195                                 if (xs.Types [qname] != null)
196                                         return resolveParameters ((XmlSchemaElement) xs.Types [qname]., msgdescr, importer);
197
198                         //FIXME: What to do here?
199                         throw new Exception ("Could not resolve : " + qname.ToString ());*/
200                         throw new NotImplementedException ();
201                 }
202
203                 string GetCLRTypeName (QName qname)
204                 {
205                         if (qname.Namespace != "http://www.w3.org/2001/XMLSchema")
206                                 return null;
207
208                         switch (qname.Name) {
209                         case "anyURI":
210                                 return "System.String";
211                         case "boolean":
212                                 return "System.Boolean";
213
214                         /*FIXME: case "base64Binary":
215                         case "dateTime":
216                         case "duration":*/
217                         case "QName":
218                                 return "System.String";
219                         case "decimal":
220                                 return "System.Decimal";
221                         case "double":
222                                 return "System.Double";
223                         case "float":
224                                 return "System.Double";
225                         case "byte":
226                                 return "System.SByte";
227                         case "short":
228                                 return "System.Int16";
229                         case "int":
230                                 return "System.Int32";
231                         case "long":
232                                 return "System.Int64";
233                         case "unsignedByte":
234                                 return "System.Byte";
235                         case "unsignedShort":
236                                 return "System.UInt16";
237                         case "unsignedInt":
238                                 return "System.UInt32";
239                         case "unsignedLong":
240                                 return "System.UInt64";
241                         case "string":
242                                 return "System.String";
243                         /* FIXME:
244                         case "anyType":
245                                 return true;
246                         default:
247                                 return false;*/
248                         }
249
250                         return null;
251                 }
252
253                 void resolveParticle (XmlSchemaImporter schema_importer, 
254                                 XmlSchemaParticle particle, 
255                                 List<MessagePartDescription> parts, 
256                                 string ns, 
257                                 int depth)
258                 {
259                         if (particle is XmlSchemaGroupBase) {
260                                 //sequence, 
261                                 //FIXME: others?
262                                 if (depth <= 0)
263                                         return;
264
265                                 XmlSchemaGroupBase groupBase = particle as XmlSchemaGroupBase;
266                                 foreach (XmlSchemaParticle item in groupBase.Items)
267                                         resolveParticle (schema_importer, item, parts, ns, depth - 1);
268
269                                 return;
270                         }
271
272                         XmlSchemaElement elem = particle as XmlSchemaElement;
273                         if (elem == null)
274                                 return;
275
276                         MessagePartDescription msg_part = null;
277                         
278                         XmlSchemaComplexType ct = elem.ElementSchemaType as XmlSchemaComplexType;
279                         if (ct == null) {
280                                 //Not a complex type
281                                 XmlSchemaSimpleType simple = elem.ElementSchemaType as XmlSchemaSimpleType;
282                                 msg_part = new MessagePartDescription (
283                                                 elem.Name, ns);
284                                 if (elem.SchemaType != null)
285                                         msg_part.XmlTypeMapping = schema_importer.ImportTypeMapping (elem.QualifiedName);
286                                 else
287                                         msg_part.XmlTypeMapping = schema_importer.ImportSchemaType (elem.SchemaTypeName);
288                                 msg_part.TypeName = new QName (GetCLRTypeName (elem.SchemaTypeName), "");
289                                 parts.Add (msg_part);
290
291                                 return;
292                         }
293
294                         if (depth > 0) {
295                                 resolveParticle (schema_importer, ct.ContentTypeParticle, parts, ns, depth - 1);
296                                 return;
297                         }
298
299                         //depth <= 0
300                         msg_part = new MessagePartDescription (elem.Name, ns);
301                         if (elem.SchemaType != null)
302                                 msg_part.XmlTypeMapping = schema_importer.ImportTypeMapping (elem.QualifiedName);
303                         else
304                                 msg_part.XmlTypeMapping = schema_importer.ImportSchemaType (elem.SchemaTypeName);
305                         msg_part.TypeName = elem.SchemaTypeName;
306
307                         parts.Add (msg_part);
308                 }
309
310                 void IWsdlImportExtension.ImportEndpoint (WsdlImporter importer,
311                         WsdlEndpointConversionContext context)
312                 {
313                 }
314         }
315 }