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