Merge pull request #853 from echampet/onclick
[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                         foreach (Type ifaceType in Type.GetInterfaces ()) {
114                                 o = ifaceType.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
115                                 if (o.Length > 0) {
116                                         defaultBindingName = ifaceType.Name + ProtocolName;
117                                         foreach (WebServiceBindingAttribute at in o)
118                                                 AddBinding (new BindingInfo (at, defaultBindingName, LogicalType.WebServiceNamespace));
119                                 }
120                         }
121                 }
122                 
123                 public WsiProfiles WsiClaims {
124                         get {
125                                 return (((BindingInfo) Bindings [0]).WebServiceBindingAttribute != null) ?
126                                         ((BindingInfo) Bindings [0]).WebServiceBindingAttribute.ConformsTo : WsiProfiles.None;
127                         }
128                 }
129                 
130                 public LogicalTypeInfo LogicalType
131                 {
132                         get { return logicalType; }
133                 }
134                 
135                 public Type Type
136                 {
137                         get { return logicalType.Type; }
138                 }
139                 
140                 public string DefaultBinding
141                 {
142                         get { return defaultBinding; }
143                 }
144                 
145                 public virtual XmlReflectionImporter XmlImporter 
146                 {
147                         get { return null; }
148                 }
149
150                 public virtual SoapReflectionImporter SoapImporter 
151                 {
152                         get { return null; }
153                 }
154                 
155                 public virtual string ProtocolName
156                 {
157                         get { return null; }
158                 }
159                 
160                 public XmlSerializer GetSerializer (int n)
161                 {
162                         return serializers [n];
163                 }
164                 
165                 public int RegisterSerializer (XmlMapping map)
166                 {
167                         if (mappings == null) mappings = new ArrayList ();
168                         return mappings.Add (map);
169                 }
170
171                 public void Initialize ()
172                 {
173                         BuildTypeMethods ();
174                         
175                         if (mappings != null)
176                         {
177                                 // Build all the serializers at once
178                                 XmlMapping[] maps = (XmlMapping[]) mappings.ToArray(typeof(XmlMapping));
179                                 serializers = XmlSerializer.FromMappings (maps);
180                         }
181                 }
182                 
183                 //
184                 // Extract all method information
185                 //
186                 protected virtual void BuildTypeMethods ()
187                 {
188                         bool isClientProxy = typeof(WebClientProtocol).IsAssignableFrom (Type);
189
190                         ArrayList metStubs = new ArrayList ();
191                         foreach (LogicalMethodInfo mi in logicalType.LogicalMethods)
192                         {
193                                 if (!isClientProxy && mi.CustomAttributeProvider.GetCustomAttributes (typeof(WebMethodAttribute), true).Length == 0)
194                                         continue;
195                                         
196                                 MethodStubInfo msi = CreateMethodStubInfo (this, mi, isClientProxy);
197
198                                 if (msi == null)
199                                         continue;
200
201                                 if (name_to_method.ContainsKey (msi.Name)) {
202                                         string msg = "Both " + msi.MethodInfo.ToString () + " and " + GetMethod (msi.Name).MethodInfo + " use the message name '" + msi.Name + "'. ";
203                                         msg += "Use the MessageName property of WebMethod custom attribute to specify unique message names for the methods";
204                                         throw new InvalidOperationException (msg);
205                                 }
206                                 
207                                 name_to_method [msi.Name] = msi;
208                                 metStubs.Add (msi);
209                         }
210                         methods = (MethodStubInfo[]) metStubs.ToArray (typeof (MethodStubInfo));
211                 }
212                 
213                 protected abstract MethodStubInfo CreateMethodStubInfo (TypeStubInfo typeInfo, LogicalMethodInfo methodInfo, bool isClientProxy);
214                 
215                 public MethodStubInfo GetMethod (string name)
216                 {
217                         return (MethodStubInfo) name_to_method [name];
218                 }
219
220                 public MethodStubInfo[] Methods
221                 {
222                         get { return methods; }
223                 }
224                 
225                 internal ArrayList Bindings
226                 {
227                         get { return bindings; }
228                 }
229                 
230                 internal void AddBinding (BindingInfo info)
231                 {
232                         bindings.Add (info);
233                 }
234
235                 internal void AddBindingAt (int pos, BindingInfo info)
236                 {
237                         bindings.Insert (pos, info);
238                 }
239                 
240                 internal BindingInfo GetBinding (string name)
241                 {
242                         if (name == null || name.Length == 0) return (BindingInfo) bindings[0];
243                         
244                         for (int n = 0; n < bindings.Count; n++)
245                                 if (((BindingInfo)bindings[n]).Name == name) return (BindingInfo)bindings[n];
246                         return null;
247                 }
248         }
249         
250         internal class BindingInfo
251         {
252                 public BindingInfo (WebServiceBindingAttribute at, string name, string ns)
253                 {
254                         if (at != null) {
255                                 Name = at.Name;
256                                 Namespace = at.Namespace;
257                                 Location = at.Location;
258                                 WebServiceBindingAttribute = at;
259                         }
260
261                         if (Name == null || Name.Length == 0)
262                                 Name = name;
263
264                         if (Namespace == null || Namespace.Length == 0)
265                                 Namespace = ns;
266                 }
267                 
268                 public readonly string Name;
269                 public readonly string Namespace;
270                 public readonly string Location;
271                 public readonly WebServiceBindingAttribute WebServiceBindingAttribute;
272         }
273
274         //
275         // Manages type stubs
276         //
277         internal class TypeStubManager 
278         {
279                 static Hashtable type_to_manager;
280                 
281                 static TypeStubManager ()
282                 {
283                         type_to_manager = new Hashtable ();
284                 }
285
286                 static internal TypeStubInfo GetTypeStub (Type t, string protocolName)
287                 {
288                         LogicalTypeInfo tm = GetLogicalTypeInfo (t);
289                         return tm.GetTypeStub (protocolName);
290                 }
291                 
292                 //
293                 // This needs to be thread safe
294                 //
295                 static internal LogicalTypeInfo GetLogicalTypeInfo (Type t)
296                 {
297                         lock (type_to_manager)
298                         {
299                                 LogicalTypeInfo tm = (LogicalTypeInfo) type_to_manager [t];
300         
301                                 if (tm != null)
302                                         return tm;
303
304                                 tm = new LogicalTypeInfo (t);
305                                 type_to_manager [t] = tm;
306
307                                 return tm;
308                         }
309                 }
310         }
311 }