53570492a03f54795bb12fb6b8db4d1e554eef7e
[mono.git] / mcs / class / System.Runtime.Serialization.Formatters.Soap / System.Runtime.Serialization.Formatters.Soap / SoapTypeMapper.cs
1 // created on 09/04/2003 at 18:58
2 //
3 //      System.Runtime.Serialization.Formatters.Soap.SoapTypeMapper
4 //
5 //      Authors:
6 //              Jean-Marc Andre (jean-marc.andre@polymtl.ca)
7 //
8
9 using System;
10 using System.Reflection;
11 using System.Collections;
12 using System.Runtime.Remoting;
13 using System.Xml;
14 using System.Xml.Serialization;
15 using System.Runtime.Serialization.Formatters;
16 using System.Xml.Schema;
17 using System.Runtime.Remoting.Metadata.W3cXsd2001;
18 using System.Globalization;
19
20 namespace System.Runtime.Serialization.Formatters.Soap {
21
22         internal class Element
23         {
24                 private string _prefix;
25                 private string _localName;
26                 private string _namespaceURI;
27
28                 public Element(string prefix, string localName, string namespaceURI) 
29                 {
30                         _prefix = prefix;
31                         _localName = localName;
32                         _namespaceURI = namespaceURI;
33                 }
34
35                 public Element(string localName, string namespaceURI): this(null, localName, namespaceURI)
36                 {
37                 }
38
39                 public string Prefix
40                 {
41                         get
42                         {
43                                 return _prefix;
44                         }
45                 }
46
47                 public string LocalName
48                 {
49                         get
50                         {
51                                 return _localName;
52                         }
53                 }
54
55                 public string NamespaceURI 
56                 {
57                         get 
58                         {
59                                 return _namespaceURI;
60                         }
61                 }
62
63                 public override bool Equals(object obj) 
64                 {
65                         Element element = obj as Element;
66                         return (_localName == XmlConvert.DecodeName(element._localName) &&
67                                 _namespaceURI == XmlConvert.DecodeName(element._namespaceURI))?true:false;
68                 }
69
70                 public override int GetHashCode()
71                 {
72                         return (String.Format("{0} {1}", 
73                                 XmlConvert.DecodeName(_localName),
74                                 XmlConvert.DecodeName(_namespaceURI))).GetHashCode();
75                 }
76
77                 public override string ToString() 
78                 {
79                         return string.Format("Element.Prefix = {0}, Element.LocalName = {1}, Element.NamespaceURI = {2}", this.Prefix, this.LocalName, this.NamespaceURI);
80                 }
81         }
82
83         internal class SoapTypeMapper {
84                 private static Hashtable xmlNodeToTypeTable = new Hashtable();
85                 private static Hashtable typeToXmlNodeTable = new Hashtable();
86                 public static readonly string SoapEncodingNamespace = "http://schemas.xmlsoap.org/soap/encoding/";
87                 public static readonly string SoapEncodingPrefix = "SOAP-ENC";
88                 public static readonly string SoapEnvelopeNamespace = "http://schemas.xmlsoap.org/soap/envelope/";
89                 public static readonly string SoapEnvelopePrefix = "SOAP-ENV";
90                 internal static readonly string SoapEnvelope;
91                 private XmlTextWriter _xmlWriter;
92                 private long _prefixNumber;
93                 private Hashtable namespaceToPrefixTable = new Hashtable();
94                 private SerializationBinder _binder;
95                 private static ArrayList _canBeValueTypeList;
96                 private FormatterAssemblyStyle _assemblyFormat = FormatterAssemblyStyle.Full;
97                 private Element elementString;
98
99
100                 // Constructor used by SoapReader
101                 public SoapTypeMapper(SerializationBinder binder) 
102                 {
103                         _binder = binder;
104                 }
105
106                 // Constructor used by SoapWriter
107                 public SoapTypeMapper(
108                         XmlTextWriter xmlWriter, 
109                         FormatterAssemblyStyle assemblyFormat,
110                         FormatterTypeStyle typeFormat) 
111                 {
112                         _xmlWriter = xmlWriter;
113                         _assemblyFormat = assemblyFormat;
114                         _prefixNumber = 1;
115                         Element element;
116                         Type elementType;
117                         elementType = typeof(string);
118                         if(typeFormat == FormatterTypeStyle.XsdString)\r
119                         {
120                                 elementString = new Element("xsd", "string", XmlSchema.Namespace);
121                         }
122                         else
123                         {
124                                 elementString = new Element(SoapEncodingPrefix, "string", SoapEncodingNamespace);
125                         }
126 //                      typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
127                 }
128                 
129                 static SoapTypeMapper() {
130 //                      SoapEnvelope = String.Format(
131 //                              "<{0}:Envelope xmlns:{0}='{1}' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='{2}' xmlns:{3}='{4}' xmlns:clr='{5}' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'/>",
132 //                              SoapEnvelopePrefix,
133 //                              SoapEnvelopeNamespace,
134 //                              XmlSchema.Namespace,
135 //                              SoapEncodingPrefix,
136 //                              SoapEncodingNamespace,
137 //                              SoapServices.XmlNsForClrType);
138                         _canBeValueTypeList = new ArrayList();
139                         _canBeValueTypeList.Add(typeof(DateTime).ToString());
140                         _canBeValueTypeList.Add(typeof(TimeSpan).ToString());
141                         _canBeValueTypeList.Add(typeof(string).ToString());
142                         _canBeValueTypeList.Add(typeof(decimal).ToString());
143                         _canBeValueTypeList.Sort();
144                         InitMappingTables();
145                         
146                 }
147
148                 public Type this[Element element]
149                 {
150                         get 
151                         {
152                                 Type type = null;
153
154                                 string localName = XmlConvert.DecodeName(element.LocalName);
155                                 string namespaceURI = XmlConvert.DecodeName(element.NamespaceURI);
156                                 string typeNamespace, assemblyName;
157                                 SoapServices.DecodeXmlNamespaceForClrTypeNamespace(
158                                         element.NamespaceURI, 
159                                         out typeNamespace, 
160                                         out assemblyName);
161                                 string typeName = typeNamespace + Type.Delimiter + localName;
162
163                                 if(assemblyName != null && assemblyName != string.Empty && _binder != null) 
164                                 {
165                                         type = _binder.BindToType(assemblyName, typeName);
166                                 }
167                                 if(type == null) 
168                                 {
169                                         string assemblyQualifiedName = (string)xmlNodeToTypeTable[element];
170                                         if(assemblyQualifiedName != null)
171                                                 type = Type.GetType(assemblyQualifiedName);
172                                         else
173                                         { 
174
175                                                 type = Type.GetType(element.LocalName);
176                                                 if(type == null) 
177                                                 { 
178
179                                                         type = Type.GetType(typeName);
180                                                         if(type == null) 
181                                                         {
182
183                                                                 if(assemblyName == null || assemblyName == String.Empty)
184                                                                         throw new SerializationException(
185                                                                                 String.Format("Parse Error, no assembly associated with XML key {0} {1}", 
186                                                                                 localName, 
187                                                                                 namespaceURI));
188                                                                 type = FormatterServices.GetTypeFromAssembly(
189                                                                         Assembly.Load(assemblyName), 
190                                                                         typeName);
191                                                         }
192                                                 }
193                                         }
194                                         if(type == null)
195                                                 throw new SerializationException();
196                                 }
197                                 return type;
198                         }
199                 }
200
201
202                 public Element this[string typeFullName, string assemblyName]
203                 {
204                         get 
205                         {
206                                 Element element;
207                                 string typeNamespace = string.Empty;
208                                 string typeName = typeFullName;
209                                 if(_assemblyFormat == FormatterAssemblyStyle.Simple)\r
210                                 {
211                                         string[] items = assemblyName.Split(',');
212                                         assemblyName = items[0];
213                                 }
214                                 string assemblyQualifiedName = typeFullName + ", " + assemblyName;
215                                 element = (Element) typeToXmlNodeTable[assemblyQualifiedName];
216                                 if(element == null)
217                                 {
218                                         int typeNameIndex = typeFullName.LastIndexOf('.');
219                                         if(typeNameIndex != -1) 
220                                         {
221                                                 typeNamespace = typeFullName.Substring(0, typeNameIndex);
222                                                 typeName = typeFullName.Substring(typeNamespace.Length + 1);
223                                         }
224                                         string namespaceURI = 
225                                                 SoapServices.CodeXmlNamespaceForClrTypeNamespace(
226                                                 typeNamespace, 
227                                                 (!assemblyName.StartsWith("mscorlib"))?assemblyName:String.Empty);
228                                         string prefix = (string) namespaceToPrefixTable[namespaceURI];
229                                         if(prefix == null || prefix == string.Empty)
230                                         {
231                                                 prefix = "a" + (_prefixNumber++).ToString();
232                                                 namespaceToPrefixTable[namespaceURI] = prefix;
233
234                                         }
235                                         element = new Element(
236                                                 prefix, 
237                                                 XmlConvert.EncodeName(typeName), 
238                                                 namespaceURI);
239                                 }
240                                 return element;
241                         }
242                 }
243
244                 public Element this[Type type]
245                 {
246                         get 
247                         {
248                                 if(type == typeof(string)) return elementString;
249                                 Element element = (Element) typeToXmlNodeTable[type.AssemblyQualifiedName];
250                                 if(element == null)
251                                 {
252                                         element = this[type.FullName, type.Assembly.FullName];
253 //                                      if(_assemblyFormat == FormatterAssemblyStyle.Full)
254 //                                              element = this[type.FullName, type.Assembly.FullName];
255 //                                      else
256 //                                              element = this[type.FullName, type.Assembly.GetName().Name];
257
258                                 }
259                                 else
260                                 {
261                                         element = new Element((element.Prefix == null)?_xmlWriter.LookupPrefix(element.NamespaceURI):element.Prefix, element.LocalName, element.NamespaceURI);
262                                 }
263                                 if(element == null)
264                                         throw new SerializationException("Oooops");
265                                 return element;
266                         }
267                 }
268
269                 public static bool CanBeValue(Type type)
270                 {
271                         if(type.IsPrimitive) return true;
272                         if(type.IsEnum) return true;
273                         if(_canBeValueTypeList.BinarySearch(type.ToString()) >= 0) 
274                         {
275                                 return true;
276                         }
277                         return false;
278                 }
279
280                 private static void InitMappingTables() 
281                 {
282                         Element element;
283                         Type elementType;
284                         element = new Element("Array", SoapEncodingNamespace);
285                         elementType = typeof(System.Array);
286                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
287                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
288
289                         element = new Element("string", XmlSchema.Namespace);
290                         elementType = typeof(string);
291                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
292 //                      typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
293
294                         element = new Element("string", SoapEncodingNamespace);
295                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
296
297                         element = new Element("long", XmlSchema.Namespace);
298                         elementType = typeof(long);
299                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
300                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
301
302                         element = new Element("int", XmlSchema.Namespace);
303                         elementType = typeof(int);
304                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
305                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
306
307                         element = new Element("float", XmlSchema.Namespace);
308                         elementType = typeof(float);
309                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
310                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
311
312                         element = new Element("decimal", XmlSchema.Namespace);
313                         elementType = typeof(decimal);
314                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
315                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
316
317                         element = new Element("short", XmlSchema.Namespace);
318                         elementType = typeof(short);
319                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
320                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
321
322                         element = new Element("anyType", XmlSchema.Namespace);
323                         elementType = typeof(object);
324                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
325                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
326
327                         element = new Element("dateTime", XmlSchema.Namespace);
328                         elementType = typeof(DateTime);
329                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
330                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
331
332                         element = new Element("duration", XmlSchema.Namespace);
333                         elementType = typeof(TimeSpan);
334                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
335                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
336
337                         element = new Element("Fault", SoapEnvelopeNamespace);
338                         elementType = typeof(System.Runtime.Serialization.Formatters.SoapFault);
339                         xmlNodeToTypeTable.Add(element, elementType.AssemblyQualifiedName);
340                         typeToXmlNodeTable.Add(elementType.AssemblyQualifiedName, element);
341
342
343                 }
344                 
345                 public static string GetXsdValue (object value)
346                 {
347                         if (value is DateTime) {
348                                 return SoapDateTime.ToString ((DateTime)value);
349                         }
350                         else if (value is decimal) {
351                                 return ((decimal) value).ToString (CultureInfo.InvariantCulture);
352                         }
353                         else if (value is double) {
354                                 return ((double) value).ToString (CultureInfo.InvariantCulture);
355                         }
356                         else if (value is float) {
357                                 return ((float) value).ToString (CultureInfo.InvariantCulture);
358                         }
359                         else if (value is TimeSpan) {
360                                 return SoapDuration.ToString ((TimeSpan)value);
361                         }
362                         else {
363                                 return value.ToString ();
364                         }
365                 }
366                 
367                 public static object ParseXsdValue (string value, Type type)
368                 {
369                         if (type == typeof(DateTime)) {
370                                 return SoapDateTime.Parse (value);
371                         }
372                         else if (type == typeof(decimal)) {
373                                 return decimal.Parse (value, CultureInfo.InvariantCulture);
374                         }
375                         else if (type == typeof(double)) {
376                                 return double.Parse (value, CultureInfo.InvariantCulture);
377                         }
378                         else if (type == typeof(float)) {
379                                 return float.Parse (value, CultureInfo.InvariantCulture);
380                         }
381                         else if (type == typeof (TimeSpan)) {
382                                 return SoapDuration.Parse (value);
383                         }
384                         else if(type.IsEnum) {
385                                 return Enum.Parse(type, value);
386                         }
387                         else {
388                                 return Convert.ChangeType (value, type, CultureInfo.InvariantCulture);
389                         }
390                 }
391
392         }
393 }