Merge pull request #2247 from ivmai/match-ext-libgc-api
[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         [System.Runtime.InteropServices.ComVisible (true)]
44         public class SoapServices
45         {
46                 static Hashtable _xmlTypes = new Hashtable ();
47                 static Hashtable _xmlElements = new Hashtable ();
48                 static Hashtable _soapActions = new Hashtable ();
49                 static Hashtable _soapActionsMethods = new Hashtable ();
50                 static Hashtable _typeInfos = new Hashtable ();
51                 
52                 class TypeInfo
53                 {
54                         public Hashtable Attributes;
55                         public Hashtable Elements;
56                 }
57                 
58                 // Private constructor: nobody instantiates this class
59                 private SoapServices () {}
60                 
61                 // properties
62         
63                 public static string XmlNsForClrType 
64                 { 
65                         get { return "http://schemas.microsoft.com/clr/"; }
66                 }
67                 
68                 public static string XmlNsForClrTypeWithAssembly 
69                 {       
70                         get { return "http://schemas.microsoft.com/clr/assem/"; }
71                 }
72
73                 public static string XmlNsForClrTypeWithNs 
74                 {
75                         get { return "http://schemas.microsoft.com/clr/ns/"; }
76                 }
77
78                 public static string XmlNsForClrTypeWithNsAndAssembly
79                 {
80                         get { return "http://schemas.microsoft.com/clr/nsassem/"; }
81                 }
82
83                 
84                 // public methods
85
86                 public static string CodeXmlNamespaceForClrTypeNamespace (string typeNamespace, 
87                                                                         string assemblyName) 
88                 {
89                         // If assemblyName is empty, then use the corlib namespace
90
91                         if (assemblyName == string.Empty)
92                                 return XmlNsForClrTypeWithNs + typeNamespace;
93                         else if (typeNamespace == string.Empty)
94                                 return EncodeNs (XmlNsForClrTypeWithAssembly + assemblyName);
95                         else
96                                 return EncodeNs (XmlNsForClrTypeWithNsAndAssembly + typeNamespace + "/" + assemblyName);
97                 }
98
99                 public static bool DecodeXmlNamespaceForClrTypeNamespace (string inNamespace, 
100                                                                         out string typeNamespace, 
101                                                                         out string assemblyName) {
102
103                         if (inNamespace == null) throw new ArgumentNullException ("inNamespace");
104
105                         inNamespace = DecodeNs (inNamespace);
106                         typeNamespace = null;
107                         assemblyName = null;
108
109                         if (inNamespace.StartsWith(XmlNsForClrTypeWithNsAndAssembly))
110                         {
111                                 int typePos = XmlNsForClrTypeWithNsAndAssembly.Length;
112                                 if (typePos >= inNamespace.Length) return false;
113                                 int assemPos = inNamespace.IndexOf ('/', typePos+1);
114                                 if (assemPos == -1) return false;
115                                 typeNamespace = inNamespace.Substring (typePos, assemPos - typePos);
116                                 assemblyName = inNamespace.Substring (assemPos+1);
117                                 return true;
118                         }
119                         else if (inNamespace.StartsWith(XmlNsForClrTypeWithNs))
120                         {
121                                 int typePos = XmlNsForClrTypeWithNs.Length;
122                                 typeNamespace = inNamespace.Substring (typePos);
123                                 return true;
124                         }
125                         else if (inNamespace.StartsWith(XmlNsForClrTypeWithAssembly))
126                         {
127                                 int typePos = XmlNsForClrTypeWithAssembly.Length;
128                                 assemblyName = inNamespace.Substring (typePos);
129                                 return true;
130                         }
131                         else
132                                 return false;
133                 }
134
135                 public static void GetInteropFieldTypeAndNameFromXmlAttribute (Type containingType,
136                                                                                 string xmlAttribute, string xmlNamespace,
137                                                                                 out Type type, out string name) 
138                 {
139                         TypeInfo tf = (TypeInfo) _typeInfos [containingType];
140                         Hashtable ht = tf != null ? tf.Attributes : null;
141                         GetInteropFieldInfo (ht, xmlAttribute, xmlNamespace, out type, out name);
142                 }
143
144                 public static void GetInteropFieldTypeAndNameFromXmlElement (Type containingType,
145                                                                                 string xmlElement, string xmlNamespace,
146                                                                                 out Type type, out string name) 
147                 {
148                         TypeInfo tf = (TypeInfo) _typeInfos [containingType];
149                         Hashtable ht = tf != null ? tf.Elements : null;
150                         GetInteropFieldInfo (ht, xmlElement, xmlNamespace, out type, out name);
151                 }
152
153                 static void GetInteropFieldInfo (Hashtable fields, 
154                                                                                 string xmlName, string xmlNamespace,
155                                                                                 out Type type, out string name) 
156                 {
157                         if (fields != null)
158                         {
159                                 FieldInfo field = (FieldInfo) fields [GetNameKey (xmlName, xmlNamespace)];
160                                 if (field != null)
161                                 {
162                                         type = field.FieldType;
163                                         name = field.Name;
164                                         return;
165                                 }
166                         }
167                         type = null;
168                         name = null;
169                 }
170                 
171                 static string GetNameKey (string name, string namspace)
172                 {
173                         if (namspace == null) return name;
174                         else return name + " " + namspace;
175                 }
176
177                 public static Type GetInteropTypeFromXmlElement (string xmlElement, string xmlNamespace) 
178                 {
179                         lock (_xmlElements.SyncRoot)
180                         {
181                                 return (Type) _xmlElements [xmlElement + " " + xmlNamespace];
182                         }
183                 }
184                         
185                 public static Type GetInteropTypeFromXmlType (string xmlType, string xmlTypeNamespace) 
186                 {
187                         lock (_xmlTypes.SyncRoot)
188                         {
189                                 return (Type) _xmlTypes [xmlType + " " + xmlTypeNamespace];
190                         }
191                 }
192
193                 private static string GetAssemblyName(MethodBase mb)
194                 {
195                         if (mb.DeclaringType.Assembly == typeof (object).Assembly)
196                                 return string.Empty;
197                         else
198                                 return mb.DeclaringType.Assembly.GetName().Name;
199                 }
200
201                 public static string GetSoapActionFromMethodBase (MethodBase mb) 
202                 {
203                         return InternalGetSoapAction (mb);
204                 }
205
206                 public static bool GetTypeAndMethodNameFromSoapAction (string soapAction, 
207                                                                         out string typeName, 
208                                                                         out string methodName) 
209                 {
210                         lock (_soapActions.SyncRoot)
211                         {
212                                 MethodBase mb = (MethodBase) _soapActionsMethods [soapAction];
213                                 if (mb != null)
214                                 {
215                                         typeName = mb.DeclaringType.AssemblyQualifiedName;
216                                         methodName = mb.Name;
217                                         return true;
218                                 }
219                         }
220                         
221                         string type;
222                         string assembly;
223
224                         typeName = null;
225                         methodName = null;
226
227                         int i = soapAction.LastIndexOf ('#');
228                         if (i == -1) return false;
229
230                         methodName = soapAction.Substring (i+1);
231
232                         if (!DecodeXmlNamespaceForClrTypeNamespace (soapAction.Substring (0,i), out type, out assembly) )
233                                 return false;
234
235                         if (assembly == null) 
236                                 typeName = type + ", " + typeof (object).Assembly.GetName().Name;
237                         else
238                                 typeName = type + ", " + assembly;
239
240                         return true;
241                 }
242
243                 public static bool GetXmlElementForInteropType (Type type, out string xmlElement, out string xmlNamespace)
244                 {
245                         SoapTypeAttribute att = (SoapTypeAttribute) InternalRemotingServices.GetCachedSoapAttribute (type);
246                         if (!att.IsInteropXmlElement)
247                         {
248                                 xmlElement = null;
249                                 xmlNamespace = null;
250                                 return false;
251                         }
252                         
253                         xmlElement = att.XmlElementName;
254                         xmlNamespace = att.XmlNamespace;                                
255                         return true;
256                 }
257
258                 public static string GetXmlNamespaceForMethodCall (MethodBase mb) 
259                 {
260                         return CodeXmlNamespaceForClrTypeNamespace (mb.DeclaringType.FullName, GetAssemblyName(mb));
261                 }
262
263                 public static string GetXmlNamespaceForMethodResponse (MethodBase mb) 
264                 {
265                         return CodeXmlNamespaceForClrTypeNamespace (mb.DeclaringType.FullName, GetAssemblyName(mb));
266                 }
267
268                 public static bool GetXmlTypeForInteropType (Type type, out string xmlType, out string xmlTypeNamespace) 
269                 {
270                         SoapTypeAttribute att = (SoapTypeAttribute) InternalRemotingServices.GetCachedSoapAttribute (type);
271                         
272                         if (!att.IsInteropXmlType)
273                         {
274                                 xmlType = null;
275                                 xmlTypeNamespace = null;
276                                 return false;
277                         }
278                         
279                         xmlType = att.XmlTypeName;
280                         xmlTypeNamespace = att.XmlTypeNamespace;
281                         return true;
282                 }
283
284                 public static bool IsClrTypeNamespace (string namespaceString) 
285                 {
286                         return namespaceString.StartsWith (XmlNsForClrType);
287                 }
288
289                 public static bool IsSoapActionValidForMethodBase (string soapAction, MethodBase mb) 
290                 {
291                         string typeName;
292                         string methodName;
293                         GetTypeAndMethodNameFromSoapAction (soapAction, out typeName, out methodName);
294
295                         if (methodName != mb.Name) return false;
296
297                         string methodClassType = mb.DeclaringType.AssemblyQualifiedName;
298                         return typeName == methodClassType;
299                 }
300
301                 public static void PreLoad (Assembly assembly) 
302                 {
303                         foreach (Type t in assembly.GetTypes ())
304                                 PreLoad (t);
305                 }
306
307                 public static void PreLoad (Type type) 
308                 {
309                         string name, namspace;
310                         TypeInfo tf = _typeInfos [type] as TypeInfo;
311                         if (tf != null) return;
312                         
313                         if (GetXmlTypeForInteropType (type, out name, out namspace))
314                                 RegisterInteropXmlType (name, namspace, type);
315                                 
316                         if (GetXmlElementForInteropType (type, out name, out namspace))
317                                 RegisterInteropXmlElement (name, namspace, type);
318                                 
319                         lock (_typeInfos.SyncRoot)
320                         {
321                                 tf = new TypeInfo ();
322                                 FieldInfo[] fields = type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
323                                 
324                                 foreach (FieldInfo field in fields)
325                                 {
326                                         SoapFieldAttribute att = (SoapFieldAttribute) InternalRemotingServices.GetCachedSoapAttribute (field);
327                                         if (!att.IsInteropXmlElement ()) continue;
328                                         
329                                         string key = GetNameKey (att.XmlElementName, att.XmlNamespace);
330                                         if (att.UseAttribute)
331                                         {
332                                                 if (tf.Attributes == null) tf.Attributes = new Hashtable ();
333                                                 tf.Attributes [key] = field;
334                                         }
335                                         else
336                                         {
337                                                 if (tf.Elements == null) tf.Elements = new Hashtable ();
338                                                 tf.Elements [key] = field;
339                                         }
340                                 }
341                                 _typeInfos [type] = tf;
342                         }                       
343                 }
344                 
345                 public static void RegisterInteropXmlElement (string xmlElement, string xmlNamespace, Type type) 
346                 {
347                         lock (_xmlElements.SyncRoot)
348                         {
349                                 _xmlElements [xmlElement + " " + xmlNamespace] = type;
350                         }
351                 }
352
353                 public static void RegisterInteropXmlType (string xmlType, string xmlTypeNamespace, Type type) 
354                 {
355                         lock (_xmlTypes.SyncRoot)
356                         {
357                                 _xmlTypes [xmlType + " " + xmlTypeNamespace] = type;
358                         }
359                 }
360
361                 public static void RegisterSoapActionForMethodBase (MethodBase mb) 
362                 {
363                         InternalGetSoapAction (mb);
364                 }
365                 
366                 static string InternalGetSoapAction (MethodBase mb)
367                 {
368                         lock (_soapActions.SyncRoot)
369                         {
370                                 string action = (string) _soapActions [mb];
371                                 if (action == null)
372                                 {
373                                         SoapMethodAttribute att = (SoapMethodAttribute) InternalRemotingServices.GetCachedSoapAttribute (mb);
374                                         action = att.SoapAction;
375                                         _soapActions [mb] = action;
376                                         _soapActionsMethods [action] = mb;
377                                 }
378                                 return action;
379                         }
380                 }
381
382                 public static void RegisterSoapActionForMethodBase (MethodBase mb, string soapAction) 
383                 {
384                         lock (_soapActions.SyncRoot)
385                         {
386                                 _soapActions [mb] = soapAction;
387                                 _soapActionsMethods [soapAction] = mb;
388                         }
389                 }
390                 
391                 static string EncodeNs (string ns)
392                 {       
393                         // Simple url encoding for namespaces
394                         
395                         ns = ns.Replace (",","%2C");
396                         ns = ns.Replace (" ","%20");
397                         return ns.Replace ("=","%3D");
398                 }
399                 
400                 static string DecodeNs (string ns)
401                 {
402                         ns = ns.Replace ("%2C",",");
403                         ns = ns.Replace ("%20"," ");
404                         return ns.Replace ("%3D","=");
405                 }
406         }
407 }
408