New test.
[mono.git] / mcs / class / corlib / System.Runtime.Remoting / SoapServices.cs
1 //
2 // System.Runtime.Remoting.SoapServices.cs
3 //
4 // Author: Jaime Anguiano Olarra (jaime@gnome.org)
5 //         Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // (c) 2002, Jaime Anguiano Olarra
8 // 
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33
34 using System;
35 using System.Collections;
36 using System.Runtime.Remoting;
37 using System.Runtime.Remoting.Metadata;
38 using System.Reflection;
39 using System.Runtime.InteropServices;
40
41 namespace System.Runtime.Remoting {
42
43         public class SoapServices
44         {
45                 static Hashtable _xmlTypes = new Hashtable ();
46                 static Hashtable _xmlElements = new Hashtable ();
47                 static Hashtable _soapActions = new Hashtable ();
48                 static Hashtable _soapActionsMethods = new Hashtable ();
49                 static Hashtable _typeInfos = new Hashtable ();
50                 
51                 class TypeInfo
52                 {
53                         public Hashtable Attributes;
54                         public Hashtable Elements;
55                 }
56                 
57                 // Private constructor: nobody instantiates this class
58                 private SoapServices () {}
59                 
60                 // properties
61         
62                 public static string XmlNsForClrType 
63                 { 
64                         get { return "http://schemas.microsoft.com/clr/"; }
65                 }
66                 
67                 public static string XmlNsForClrTypeWithAssembly 
68                 {       
69                         get { return "http://schemas.microsoft.com/clr/assem/"; }
70                 }
71
72                 public static string XmlNsForClrTypeWithNs 
73                 {
74                         get { return "http://schemas.microsoft.com/clr/ns/"; }
75                 }
76
77                 public static string XmlNsForClrTypeWithNsAndAssembly
78                 {
79                         get { return "http://schemas.microsoft.com/clr/nsassem/"; }
80                 }
81
82                 
83                 // public methods
84
85                 public static string CodeXmlNamespaceForClrTypeNamespace (string typeNamespace, 
86                                                                         string assemblyName) 
87                 {
88                         // If assemblyName is empty, then use the corlib namespace
89
90                         if (assemblyName == string.Empty)
91                                 return XmlNsForClrTypeWithNs + typeNamespace;
92                         else if (typeNamespace == string.Empty)
93                                 return EncodeNs (XmlNsForClrTypeWithAssembly + assemblyName);
94                         else
95                                 return EncodeNs (XmlNsForClrTypeWithNsAndAssembly + typeNamespace + "/" + assemblyName);
96                 }
97
98                 public static bool DecodeXmlNamespaceForClrTypeNamespace (string inNamespace, 
99                                                                         out string typeNamespace, 
100                                                                         out string assemblyName) {
101
102                         if (inNamespace == null) throw new ArgumentNullException ("inNamespace");
103
104                         inNamespace = DecodeNs (inNamespace);
105                         typeNamespace = null;
106                         assemblyName = null;
107
108                         if (inNamespace.StartsWith(XmlNsForClrTypeWithNsAndAssembly))
109                         {
110                                 int typePos = XmlNsForClrTypeWithNsAndAssembly.Length;
111                                 if (typePos >= inNamespace.Length) return false;
112                                 int assemPos = inNamespace.IndexOf ('/', typePos+1);
113                                 if (assemPos == -1) return false;
114                                 typeNamespace = inNamespace.Substring (typePos, assemPos - typePos);
115                                 assemblyName = inNamespace.Substring (assemPos+1);
116                                 return true;
117                         }
118                         else if (inNamespace.StartsWith(XmlNsForClrTypeWithNs))
119                         {
120                                 int typePos = XmlNsForClrTypeWithNs.Length;
121                                 typeNamespace = inNamespace.Substring (typePos);
122                                 return true;
123                         }
124                         else if (inNamespace.StartsWith(XmlNsForClrTypeWithAssembly))
125                         {
126                                 int typePos = XmlNsForClrTypeWithAssembly.Length;
127                                 assemblyName = inNamespace.Substring (typePos);
128                                 return true;
129                         }
130                         else
131                                 return false;
132                 }
133
134                 public static void GetInteropFieldTypeAndNameFromXmlAttribute (Type containingType,
135                                                                                 string xmlAttribute, string xmlNamespace,
136                                                                                 out Type type, out string name) 
137                 {
138                         TypeInfo tf = (TypeInfo) _typeInfos [containingType];
139                         Hashtable ht = tf != null ? tf.Attributes : null;
140                         GetInteropFieldInfo (ht, xmlAttribute, xmlNamespace, out type, out name);
141                 }
142
143                 public static void GetInteropFieldTypeAndNameFromXmlElement (Type containingType,
144                                                                                 string xmlElement, string xmlNamespace,
145                                                                                 out Type type, out string name) 
146                 {
147                         TypeInfo tf = (TypeInfo) _typeInfos [containingType];
148                         Hashtable ht = tf != null ? tf.Elements : null;
149                         GetInteropFieldInfo (ht, xmlElement, xmlNamespace, out type, out name);
150                 }
151
152                 static void GetInteropFieldInfo (Hashtable fields, 
153                                                                                 string xmlName, string xmlNamespace,
154                                                                                 out Type type, out string name) 
155                 {
156                         if (fields != null)
157                         {
158                                 FieldInfo field = (FieldInfo) fields [GetNameKey (xmlName, xmlNamespace)];
159                                 if (field != null)
160                                 {
161                                         type = field.FieldType;
162                                         name = field.Name;
163                                         return;
164                                 }
165                         }
166                         type = null;
167                         name = null;
168                 }
169                 
170                 static string GetNameKey (string name, string namspace)
171                 {
172                         if (namspace == null) return name;
173                         else return name + " " + namspace;
174                 }
175
176                 public static Type GetInteropTypeFromXmlElement (string xmlElement, string xmlNamespace) 
177                 {
178                         lock (_xmlElements.SyncRoot)
179                         {
180                                 return (Type) _xmlElements [xmlElement + " " + xmlNamespace];
181                         }
182                 }
183                         
184                 public static Type GetInteropTypeFromXmlType (string xmlType, string xmlTypeNamespace) 
185                 {
186                         lock (_xmlTypes.SyncRoot)
187                         {
188                                 return (Type) _xmlTypes [xmlType + " " + xmlTypeNamespace];
189                         }
190                 }
191
192                 private static string GetAssemblyName(MethodBase mb)
193                 {
194                         if (mb.DeclaringType.Assembly == typeof (object).Assembly)
195                                 return string.Empty;
196                         else
197                                 return mb.DeclaringType.Assembly.GetName().Name;
198                 }
199
200                 public static string GetSoapActionFromMethodBase (MethodBase mb) 
201                 {
202                         return InternalGetSoapAction (mb);
203                 }
204
205                 public static bool GetTypeAndMethodNameFromSoapAction (string soapAction, 
206                                                                         out string typeName, 
207                                                                         out string methodName) 
208                 {
209                         lock (_soapActions.SyncRoot)
210                         {
211                                 MethodBase mb = (MethodBase) _soapActionsMethods [soapAction];
212                                 if (mb != null)
213                                 {
214                                         typeName = mb.DeclaringType.AssemblyQualifiedName;
215                                         methodName = mb.Name;
216                                         return true;
217                                 }
218                         }
219                         
220                         string type;
221                         string assembly;
222
223                         typeName = null;
224                         methodName = null;
225
226                         int i = soapAction.LastIndexOf ('#');
227                         if (i == -1) return false;
228
229                         methodName = soapAction.Substring (i+1);
230
231                         if (!DecodeXmlNamespaceForClrTypeNamespace (soapAction.Substring (0,i), out type, out assembly) )
232                                 return false;
233
234                         if (assembly == null) 
235                                 typeName = type + ", " + typeof (object).Assembly.GetName().Name;
236                         else
237                                 typeName = type + ", " + assembly;
238
239                         return true;
240                 }
241
242                 public static bool GetXmlElementForInteropType (Type type, out string xmlElement, out string xmlNamespace)
243                 {
244                         SoapTypeAttribute att = (SoapTypeAttribute) InternalRemotingServices.GetCachedSoapAttribute (type);
245                         if (!att.IsInteropXmlElement)
246                         {
247                                 xmlElement = null;
248                                 xmlNamespace = null;
249                                 return false;
250                         }
251                         
252                         xmlElement = att.XmlElementName;
253                         xmlNamespace = att.XmlNamespace;                                
254                         return true;
255                 }
256
257                 public static string GetXmlNamespaceForMethodCall (MethodBase mb) 
258                 {
259                         return CodeXmlNamespaceForClrTypeNamespace (mb.DeclaringType.FullName, GetAssemblyName(mb));
260                 }
261
262                 public static string GetXmlNamespaceForMethodResponse (MethodBase mb) 
263                 {
264                         return CodeXmlNamespaceForClrTypeNamespace (mb.DeclaringType.FullName, GetAssemblyName(mb));
265                 }
266
267                 public static bool GetXmlTypeForInteropType (Type type, out string xmlType, out string xmlTypeNamespace) 
268                 {
269                         SoapTypeAttribute att = (SoapTypeAttribute) InternalRemotingServices.GetCachedSoapAttribute (type);
270                         
271                         if (!att.IsInteropXmlType)
272                         {
273                                 xmlType = null;
274                                 xmlTypeNamespace = null;
275                                 return false;
276                         }
277                         
278                         xmlType = att.XmlTypeName;
279                         xmlTypeNamespace = att.XmlTypeNamespace;
280                         return true;
281                 }
282
283                 public static bool IsClrTypeNamespace (string namespaceString) 
284                 {
285                         return namespaceString.StartsWith (XmlNsForClrType);
286                 }
287
288                 public static bool IsSoapActionValidForMethodBase (string soapAction, MethodBase mb) 
289                 {
290                         string typeName;
291                         string methodName;
292                         GetTypeAndMethodNameFromSoapAction (soapAction, out typeName, out methodName);
293
294                         if (methodName != mb.Name) return false;
295
296                         string methodClassType = mb.DeclaringType.AssemblyQualifiedName;
297                         return typeName == methodClassType;
298                 }
299
300                 public static void PreLoad (Assembly assembly) 
301                 {
302                         foreach (Type t in assembly.GetTypes ())
303                                 PreLoad (t);
304                 }
305
306                 public static void PreLoad (Type type) 
307                 {
308                         string name, namspace;
309                         TypeInfo tf = _typeInfos [type] as TypeInfo;
310                         if (tf != null) return;
311                         
312                         if (GetXmlTypeForInteropType (type, out name, out namspace))
313                                 RegisterInteropXmlType (name, namspace, type);
314                                 
315                         if (GetXmlElementForInteropType (type, out name, out namspace))
316                                 RegisterInteropXmlElement (name, namspace, type);
317                                 
318                         lock (_typeInfos.SyncRoot)
319                         {
320                                 tf = new TypeInfo ();
321                                 FieldInfo[] fields = type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
322                                 
323                                 foreach (FieldInfo field in fields)
324                                 {
325                                         SoapFieldAttribute att = (SoapFieldAttribute) InternalRemotingServices.GetCachedSoapAttribute (field);
326                                         if (!att.IsInteropXmlElement ()) continue;
327                                         
328                                         string key = GetNameKey (att.XmlElementName, att.XmlNamespace);
329                                         if (att.UseAttribute)
330                                         {
331                                                 if (tf.Attributes == null) tf.Attributes = new Hashtable ();
332                                                 tf.Attributes [key] = field;
333                                         }
334                                         else
335                                         {
336                                                 if (tf.Elements == null) tf.Elements = new Hashtable ();
337                                                 tf.Elements [key] = field;
338                                         }
339                                 }
340                                 _typeInfos [type] = tf;
341                         }                       
342                 }
343                 
344                 public static void RegisterInteropXmlElement (string xmlElement, string xmlNamespace, Type type) 
345                 {
346                         lock (_xmlElements.SyncRoot)
347                         {
348                                 _xmlElements [xmlElement + " " + xmlNamespace] = type;
349                         }
350                 }
351
352                 public static void RegisterInteropXmlType (string xmlType, string xmlTypeNamespace, Type type) 
353                 {
354                         lock (_xmlTypes.SyncRoot)
355                         {
356                                 _xmlTypes [xmlType + " " + xmlTypeNamespace] = type;
357                         }
358                 }
359
360                 public static void RegisterSoapActionForMethodBase (MethodBase mb) 
361                 {
362                         InternalGetSoapAction (mb);
363                 }
364                 
365                 static string InternalGetSoapAction (MethodBase mb)
366                 {
367                         lock (_soapActions.SyncRoot)
368                         {
369                                 string action = (string) _soapActions [mb];
370                                 if (action == null)
371                                 {
372                                         SoapMethodAttribute att = (SoapMethodAttribute) InternalRemotingServices.GetCachedSoapAttribute (mb);
373                                         action = att.SoapAction;
374                                         _soapActions [mb] = action;
375                                         _soapActionsMethods [action] = mb;
376                                 }
377                                 return action;
378                         }
379                 }
380
381                 public static void RegisterSoapActionForMethodBase (MethodBase mb, string soapAction) 
382                 {
383                         lock (_soapActions.SyncRoot)
384                         {
385                                 _soapActions [mb] = soapAction;
386                                 _soapActionsMethods [soapAction] = mb;
387                         }
388                 }
389                 
390                 static string EncodeNs (string ns)
391                 {       
392                         // Simple url encoding for namespaces
393                         
394                         ns = ns.Replace (",","%2C");
395                         ns = ns.Replace (" ","%20");
396                         return ns.Replace ("=","%3D");
397                 }
398                 
399                 static string DecodeNs (string ns)
400                 {
401                         ns = ns.Replace ("%2C",",");
402                         ns = ns.Replace ("%20"," ");
403                         return ns.Replace ("%3D","=");
404                 }
405         }
406 }
407