* HttpSimpleClientProtocol.cs: Do not encode the request url, since it is
[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 using System.Reflection;
12 using System.Collections;
13 using System.Xml;
14 using System.Xml.Serialization;
15 using System.Web.Services;
16 using System.Web.Services.Description;
17
18 namespace System.Web.Services.Protocols {
19
20         //
21         // This class represents all the information we extract from a MethodInfo
22         // in the WebClientProtocol derivative stub class
23         //
24         internal class MethodStubInfo 
25         {
26                 internal LogicalMethodInfo MethodInfo;
27                 internal TypeStubInfo TypeStub;
28
29                 // The name used by the stub class to reference this method.
30                 internal string Name;
31                 internal WebMethodAttribute MethodAttribute;
32                 
33                 internal string OperationName
34                 {
35                         get { return MethodInfo.Name; }
36                 }
37
38                 //
39                 // Constructor
40                 //
41                 public MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source)
42                 {
43                         TypeStub = parent;
44                         MethodInfo = source;
45
46                         object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
47                         if (o.Length > 0)
48                         {
49                                 MethodAttribute = (WebMethodAttribute) o [0];
50                                 Name = MethodAttribute.MessageName;
51                                 if (Name == "") Name = source.Name;
52                         }
53                         else
54                                 Name = source.Name;
55                 }
56         }
57
58         //
59         // Holds the metadata loaded from the type stub, as well as
60         // the metadata for all the methods in the type
61         //
62         internal class TypeStubInfo 
63         {
64                 Hashtable name_to_method = new Hashtable ();
65                 MethodStubInfo[] methods;
66                 ArrayList bindings = new ArrayList ();
67                 LogicalTypeInfo logicalType;
68                 string defaultBinding;
69                 ArrayList mappings;
70                 XmlSerializer[] serializers;
71
72                 public TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
73                 {
74                         this.logicalType = logicalTypeInfo;
75
76                         defaultBinding = logicalType.WebServiceName + ProtocolName;
77                         BindingInfo binfo = new BindingInfo (defaultBinding, logicalType.WebServiceNamespace);
78                         Bindings.Add (binfo);
79                 }
80                 
81                 public LogicalTypeInfo LogicalType
82                 {
83                         get { return logicalType; }
84                 }
85                 
86                 public Type Type
87                 {
88                         get { return logicalType.Type; }
89                 }
90                 
91                 public string DefaultBinding
92                 {
93                         get { return defaultBinding; }
94                 }
95                 
96                 public virtual XmlReflectionImporter XmlImporter 
97                 {
98                         get { return null; }
99                 }
100
101                 public virtual SoapReflectionImporter SoapImporter 
102                 {
103                         get { return null; }
104                 }
105                 
106                 public virtual string ProtocolName
107                 {
108                         get { return null; }
109                 }
110                 
111                 public XmlSerializer GetSerializer (int n)
112                 {
113                         return serializers [n];
114                 }
115                 
116                 public int RegisterSerializer (XmlMapping map)
117                 {
118                         if (mappings == null) mappings = new ArrayList ();
119                         return mappings.Add (map);
120                 }
121
122                 public void Initialize ()
123                 {
124                         BuildTypeMethods ();
125                         
126                         if (mappings != null)
127                         {
128                                 // Build all the serializers at once
129                                 XmlMapping[] maps = (XmlMapping[]) mappings.ToArray(typeof(XmlMapping));
130                                 serializers = XmlSerializer.FromMappings (maps);
131                         }
132                 }
133                 
134                 //
135                 // Extract all method information
136                 //
137                 protected virtual void BuildTypeMethods ()
138                 {
139                         bool isClientProxy = typeof(WebClientProtocol).IsAssignableFrom (Type);
140
141                         ArrayList metStubs = new ArrayList ();
142                         foreach (LogicalMethodInfo mi in logicalType.LogicalMethods)
143                         {
144                                 if (!isClientProxy && mi.CustomAttributeProvider.GetCustomAttributes (typeof(WebMethodAttribute), true).Length == 0)
145                                         continue;
146                                         
147                                 MethodStubInfo msi = CreateMethodStubInfo (this, mi, isClientProxy);
148
149                                 if (msi == null)
150                                         continue;
151
152                                 if (name_to_method.ContainsKey (msi.Name)) {
153                                         string msg = "Both " + msi.MethodInfo.ToString () + " and " + GetMethod (msi.Name).MethodInfo + " use the message name '" + msi.Name + "'. ";
154                                         msg += "Use the MessageName property of WebMethod custom attribute to specify unique message names for the methods";
155                                         throw new InvalidOperationException (msg);
156                                 }
157                                 
158                                 name_to_method [msi.Name] = msi;
159                                 metStubs.Add (msi);
160                         }
161                         methods = (MethodStubInfo[]) metStubs.ToArray (typeof (MethodStubInfo));
162                 }
163                 
164                 protected virtual MethodStubInfo CreateMethodStubInfo (TypeStubInfo typeInfo, LogicalMethodInfo methodInfo, bool isClientProxy)
165                 {
166                         return new MethodStubInfo (typeInfo, methodInfo);
167                 }
168                 
169                 public MethodStubInfo GetMethod (string name)
170                 {
171                         return (MethodStubInfo) name_to_method [name];
172                 }
173
174                 public MethodStubInfo[] Methods
175                 {
176                         get { return methods; }
177                 }
178                 
179                 internal ArrayList Bindings
180                 {
181                         get { return bindings; }
182                 }
183                 
184                 internal BindingInfo GetBinding (string name)
185                 {
186                         for (int n=0; n<bindings.Count; n++)
187                                 if (((BindingInfo)bindings[n]).Name == name) return (BindingInfo)bindings[n];
188                         return null;
189                 }
190         }
191         
192         internal class BindingInfo
193         {
194                 public BindingInfo (WebServiceBindingAttribute at, string ns)
195                 {
196                         Name = at.Name;
197                         Namespace = at.Namespace;
198                         if (Namespace == "") Namespace = ns;
199                         Location = at.Location;
200                 }
201                 
202                 public BindingInfo (string name, string ns)
203                 {
204                         Name = name;
205                         Namespace = ns;
206                 }
207                 
208                 public string Name;
209                 public string Namespace;
210                 public string Location;
211         }
212
213
214         //
215         // This class has information abou a web service. Through providess
216         // access to the TypeStubInfo instances for each protocol.
217         //
218         internal class LogicalTypeInfo
219         {
220                 LogicalMethodInfo[] logicalMethods;
221
222                 internal string WebServiceName;
223                 internal string WebServiceNamespace;
224                 internal string WebServiceLiteralNamespace;
225                 internal string WebServiceEncodedNamespace;
226                 internal string WebServiceAbstractNamespace;
227                 internal string Description;
228                 internal Type Type;
229
230                 TypeStubInfo soapProtocol;
231                 TypeStubInfo httpGetProtocol;
232                 TypeStubInfo httpPostProtocol;
233                 
234                 public LogicalTypeInfo (Type t)
235                 {
236                         this.Type = t;
237
238                         object [] o = Type.GetCustomAttributes (typeof (WebServiceAttribute), false);
239                         if (o.Length == 1){
240                                 WebServiceAttribute a = (WebServiceAttribute) o [0];
241                                 WebServiceName = (a.Name != string.Empty) ? a.Name : Type.Name;
242                                 WebServiceNamespace = (a.Namespace != string.Empty) ? a.Namespace : WebServiceAttribute.DefaultNamespace;
243                                 Description = a.Description;
244                         } else {
245                                 WebServiceName = Type.Name;
246                                 WebServiceNamespace = WebServiceAttribute.DefaultNamespace;
247                         }
248                         
249                         // Determine the namespaces for literal and encoded schema types
250                         
251                         bool encoded = false;
252                         
253                         o = t.GetCustomAttributes (typeof(SoapDocumentServiceAttribute), true);
254                         if (o.Length > 0) {
255                                 SoapDocumentServiceAttribute at = (SoapDocumentServiceAttribute) o[0];
256                                 encoded = (at.Use == SoapBindingUse.Encoded);
257                         }
258                         else if (t.GetCustomAttributes (typeof(SoapRpcServiceAttribute), true).Length > 0)
259                                 encoded = true;
260                         
261                         string sep = WebServiceNamespace.EndsWith ("/") ? "" : "/";
262                         
263                         if (encoded) {
264                                 WebServiceEncodedNamespace = WebServiceNamespace;
265                                 WebServiceLiteralNamespace = WebServiceNamespace + sep + "literalTypes";
266                         }
267                         else {
268                                 WebServiceEncodedNamespace = WebServiceNamespace + sep + "encodedTypes";
269                                 WebServiceLiteralNamespace = WebServiceNamespace;
270                         }
271                         
272                         WebServiceAbstractNamespace = WebServiceNamespace + sep + "AbstractTypes";
273                         
274                         MethodInfo [] type_methods = Type.GetMethods (BindingFlags.Instance | BindingFlags.Public);
275                         logicalMethods = LogicalMethodInfo.Create (type_methods, LogicalMethodTypes.Sync);
276                 }
277                 
278                 public LogicalMethodInfo[] LogicalMethods
279                 {
280                         get { return logicalMethods; }
281                 }
282                 
283                 public TypeStubInfo GetTypeStub (string protocolName)
284                 {
285                         lock (this)
286                         {
287                                 switch (protocolName)
288                                 {
289                                         case "Soap": 
290                                                 if (soapProtocol == null) soapProtocol = CreateTypeStubInfo (typeof(SoapTypeStubInfo));
291                                                 return soapProtocol;
292                                         case "HttpGet":
293                                                 if (httpGetProtocol == null) httpGetProtocol = CreateTypeStubInfo (typeof(HttpGetTypeStubInfo));
294                                                 return httpGetProtocol;
295                                         case "HttpPost":
296                                                 if (httpPostProtocol == null) httpPostProtocol = CreateTypeStubInfo (typeof(HttpPostTypeStubInfo));
297                                                 return httpPostProtocol;
298                                 }
299                         }
300                         throw new InvalidOperationException ("Protocol " + protocolName + " not supported");
301                 }
302                 
303                 TypeStubInfo CreateTypeStubInfo (Type type)
304                 {
305                         TypeStubInfo tsi = (TypeStubInfo) Activator.CreateInstance (type, new object[] {this});
306                         tsi.Initialize ();
307                         return tsi;
308                 }
309                 
310                 public string GetWebServiceNamespace (SoapBindingUse use)
311                 {
312                         if (use == SoapBindingUse.Literal) return WebServiceLiteralNamespace;
313                         else return WebServiceEncodedNamespace;
314                 }
315                 
316         }
317
318         //
319         // Manages type stubs
320         //
321         internal class TypeStubManager 
322         {
323                 static Hashtable type_to_manager;
324                 
325                 static TypeStubManager ()
326                 {
327                         type_to_manager = new Hashtable ();
328                 }
329
330                 static internal TypeStubInfo GetTypeStub (Type t, string protocolName)
331                 {
332                         LogicalTypeInfo tm = GetLogicalTypeInfo (t);
333                         return tm.GetTypeStub (protocolName);
334                 }
335                 
336                 //
337                 // This needs to be thread safe
338                 //
339                 static internal LogicalTypeInfo GetLogicalTypeInfo (Type t)
340                 {
341                         LogicalTypeInfo tm = (LogicalTypeInfo) type_to_manager [t];
342
343                         if (tm != null)
344                                 return tm;
345
346                         lock (typeof (LogicalTypeInfo))
347                         {
348                                 tm = (LogicalTypeInfo) type_to_manager [t];
349
350                                 if (tm != null)
351                                         return tm;
352                                         
353                                 tm = new LogicalTypeInfo (t);
354                                 type_to_manager [t] = tm;
355
356                                 return tm;
357                         }
358                 }
359         }
360 }