28d03f04f995c30454476d569a125ac56fa326d8
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Protocols / TypeStubManager.cs
1 //
2 // Methods.cs: Information about a method and its mapping to a SOAP web service.
3 //
4 // Author:
5 //   Miguel de Icaza
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // (C) 2003 Ximian, Inc.
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Reflection;
33 using System.Collections;
34 using System.Xml;
35 using System.Xml.Serialization;
36 using System.Web.Services;
37 using System.Web.Services.Description;
38
39 namespace System.Web.Services.Protocols {
40
41         //
42         // This class represents all the information we extract from a MethodInfo
43         // in the WebClientProtocol derivative stub class
44         //
45         internal class MethodStubInfo 
46         {
47                 internal LogicalMethodInfo MethodInfo;
48                 internal TypeStubInfo TypeStub;
49
50                 // The name used by the stub class to reference this method.
51                 internal string Name;
52                 internal WebMethodAttribute MethodAttribute;
53                 
54                 internal string OperationName
55                 {
56                         get { return MethodInfo.Name; }
57                 }
58
59                 //
60                 // Constructor
61                 //
62                 public MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source)
63                 {
64                         TypeStub = parent;
65                         MethodInfo = source;
66
67                         object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
68                         if (o.Length > 0)
69                         {
70                                 MethodAttribute = (WebMethodAttribute) o [0];
71                                 Name = MethodAttribute.MessageName;
72                                 if (Name == "") Name = source.Name;
73                         }
74                         else
75                                 Name = source.Name;
76                 }
77         }
78
79         //
80         // Holds the metadata loaded from the type stub, as well as
81         // the metadata for all the methods in the type
82         //
83         internal abstract class TypeStubInfo 
84         {
85                 Hashtable name_to_method = new Hashtable ();
86                 MethodStubInfo[] methods;
87                 ArrayList bindings = new ArrayList ();
88                 LogicalTypeInfo logicalType;
89                 string defaultBinding;
90                 ArrayList mappings;
91                 XmlSerializer[] serializers;
92
93                 public TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
94                 {
95                         this.logicalType = logicalTypeInfo;
96
97                         object [] o = Type.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
98
99                         bool isClientSide = typeof (SoapHttpClientProtocol).IsAssignableFrom (Type);
100                         bool defaultAdded = false;
101
102                         string defaultBindingName = logicalType.WebServiceName + ProtocolName;
103                         if (o.Length > 0)
104                                 foreach (WebServiceBindingAttribute at in o) {
105                                         AddBinding (new BindingInfo (at, defaultBindingName, LogicalType.WebServiceNamespace));
106                                         if ((at.Name == null || at.Name.Length == 0) || (at.Name == defaultBindingName))
107                                                 defaultAdded = true;
108                                 }
109
110                         if (!defaultAdded && !isClientSide)
111                                 AddBindingAt (0, new BindingInfo (null, defaultBindingName, logicalType.WebServiceNamespace));
112
113 #if NET_2_0
114                         foreach (Type ifaceType in Type.GetInterfaces ()) {
115                                 o = ifaceType.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
116                                 if (o.Length > 0) {
117                                         defaultBindingName = ifaceType.Name + ProtocolName;
118                                         foreach (WebServiceBindingAttribute at in o)
119                                                 AddBinding (new BindingInfo (at, defaultBindingName, LogicalType.WebServiceNamespace));
120                                 }
121                         }
122 #endif
123                 }
124                 
125 #if NET_2_0
126                 public WsiProfiles WsiClaims {
127                         get {
128                                 return (((BindingInfo) Bindings [0]).WebServiceBindingAttribute != null) ?
129                                         ((BindingInfo) Bindings [0]).WebServiceBindingAttribute.ConformsTo : WsiProfiles.None;
130                         }
131                 }
132 #endif
133                 
134                 public LogicalTypeInfo LogicalType
135                 {
136                         get { return logicalType; }
137                 }
138                 
139                 public Type Type
140                 {
141                         get { return logicalType.Type; }
142                 }
143                 
144                 public string DefaultBinding
145                 {
146                         get { return defaultBinding; }
147                 }
148                 
149                 public virtual XmlReflectionImporter XmlImporter 
150                 {
151                         get { return null; }
152                 }
153
154                 public virtual SoapReflectionImporter SoapImporter 
155                 {
156                         get { return null; }
157                 }
158                 
159                 public virtual string ProtocolName
160                 {
161                         get { return null; }
162                 }
163                 
164                 public XmlSerializer GetSerializer (int n)
165                 {
166                         return serializers [n];
167                 }
168                 
169                 public int RegisterSerializer (XmlMapping map)
170                 {
171                         if (mappings == null) mappings = new ArrayList ();
172                         return mappings.Add (map);
173                 }
174
175                 public void Initialize ()
176                 {
177                         BuildTypeMethods ();
178                         
179                         if (mappings != null)
180                         {
181                                 // Build all the serializers at once
182                                 XmlMapping[] maps = (XmlMapping[]) mappings.ToArray(typeof(XmlMapping));
183                                 serializers = XmlSerializer.FromMappings (maps);
184                         }
185                 }
186                 
187                 //
188                 // Extract all method information
189                 //
190                 protected virtual void BuildTypeMethods ()
191                 {
192                         bool isClientProxy = typeof(WebClientProtocol).IsAssignableFrom (Type);
193
194                         ArrayList metStubs = new ArrayList ();
195                         foreach (LogicalMethodInfo mi in logicalType.LogicalMethods)
196                         {
197                                 if (!isClientProxy && mi.CustomAttributeProvider.GetCustomAttributes (typeof(WebMethodAttribute), true).Length == 0)
198                                         continue;
199                                         
200                                 MethodStubInfo msi = CreateMethodStubInfo (this, mi, isClientProxy);
201
202                                 if (msi == null)
203                                         continue;
204
205                                 if (name_to_method.ContainsKey (msi.Name)) {
206                                         string msg = "Both " + msi.MethodInfo.ToString () + " and " + GetMethod (msi.Name).MethodInfo + " use the message name '" + msi.Name + "'. ";
207                                         msg += "Use the MessageName property of WebMethod custom attribute to specify unique message names for the methods";
208                                         throw new InvalidOperationException (msg);
209                                 }
210                                 
211                                 name_to_method [msi.Name] = msi;
212                                 metStubs.Add (msi);
213                         }
214                         methods = (MethodStubInfo[]) metStubs.ToArray (typeof (MethodStubInfo));
215                 }
216                 
217                 protected abstract MethodStubInfo CreateMethodStubInfo (TypeStubInfo typeInfo, LogicalMethodInfo methodInfo, bool isClientProxy);
218                 
219                 public MethodStubInfo GetMethod (string name)
220                 {
221                         return (MethodStubInfo) name_to_method [name];
222                 }
223
224                 public MethodStubInfo[] Methods
225                 {
226                         get { return methods; }
227                 }
228                 
229                 internal ArrayList Bindings
230                 {
231                         get { return bindings; }
232                 }
233                 
234                 internal void AddBinding (BindingInfo info)
235                 {
236                         bindings.Add (info);
237                 }
238
239                 internal void AddBindingAt (int pos, BindingInfo info)
240                 {
241                         bindings.Insert (pos, info);
242                 }
243                 
244                 internal BindingInfo GetBinding (string name)
245                 {
246                         if (name == null || name.Length == 0) return (BindingInfo) bindings[0];
247                         
248                         for (int n = 0; n < bindings.Count; n++)
249                                 if (((BindingInfo)bindings[n]).Name == name) return (BindingInfo)bindings[n];
250                         return null;
251                 }
252         }
253         
254         internal class BindingInfo
255         {
256                 public BindingInfo (WebServiceBindingAttribute at, string name, string ns)
257                 {
258                         if (at != null) {
259                                 Name = at.Name;
260                                 Namespace = at.Namespace;
261                                 Location = at.Location;
262                                 WebServiceBindingAttribute = at;
263                         }
264
265                         if (Name == null || Name.Length == 0)
266                                 Name = name;
267
268                         if (Namespace == null || Namespace.Length == 0)
269                                 Namespace = ns;
270                 }
271                 
272                 public readonly string Name;
273                 public readonly string Namespace;
274                 public readonly string Location;
275                 public readonly WebServiceBindingAttribute WebServiceBindingAttribute;
276         }
277
278         //
279         // Manages type stubs
280         //
281         internal class TypeStubManager 
282         {
283 #if !TARGET_JVM
284                 static Hashtable type_to_manager;
285 #else
286                 const string type_to_manager_key = "TypeStubManager.type_to_manager";
287                 static Hashtable type_to_manager {
288                         get {
289                                 Hashtable hash = (Hashtable)AppDomain.CurrentDomain.GetData(type_to_manager_key);
290
291                                 if (hash != null)
292                                         return hash;
293
294                                 lock(type_to_manager_key) {
295                                         AppDomain.CurrentDomain.SetData(type_to_manager_key, new Hashtable());
296                                 }
297
298                                 return (Hashtable)AppDomain.CurrentDomain.GetData(type_to_manager_key);
299                         }
300                         set {
301                                 //do nothing: we manage our type_to_manager per domain
302                         }
303                 }
304 #endif
305                 
306                 static TypeStubManager ()
307                 {
308                         type_to_manager = new Hashtable ();
309                 }
310
311                 static internal TypeStubInfo GetTypeStub (Type t, string protocolName)
312                 {
313                         LogicalTypeInfo tm = GetLogicalTypeInfo (t);
314                         return tm.GetTypeStub (protocolName);
315                 }
316                 
317                 //
318                 // This needs to be thread safe
319                 //
320                 static internal LogicalTypeInfo GetLogicalTypeInfo (Type t)
321                 {
322                         lock (type_to_manager)
323                         {
324                                 LogicalTypeInfo tm = (LogicalTypeInfo) type_to_manager [t];
325         
326                                 if (tm != null)
327                                         return tm;
328
329                                 tm = new LogicalTypeInfo (t);
330                                 type_to_manager [t] = tm;
331
332                                 return tm;
333                         }
334                 }
335         }
336 }