2006-11-02 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / ProtocolReflector.cs
1 // 
2 // System.Web.Services.Description.ProtocolReflector.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Tim Coleman, 2002
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.Web.Services;
33 using System.Web.Services.Protocols;
34 using System.Xml.Serialization;
35 using System.Xml;
36 using System.Xml.Schema;
37 using System.Collections;
38
39 namespace System.Web.Services.Description {
40         public abstract class ProtocolReflector {
41
42                 #region Fields
43
44                 Binding binding;
45                 string defaultNamespace;
46                 MessageCollection headerMessages;
47                 Message inputMessage;
48                 LogicalMethodInfo[] methods;
49                 Operation operation;
50                 OperationBinding operationBinding;
51                 Message outputMessage;          
52                 Port port;
53                 PortType portType;
54                 string protocolName;
55                 XmlSchemaExporter schemaExporter;
56                 Service service;
57                 ServiceDescription serviceDescription;
58                 Type serviceType;
59                 string serviceUrl;
60                 SoapSchemaExporter soapSchemaExporter;
61                 MethodStubInfo methodStubInfo;
62                 TypeStubInfo typeInfo;
63                 ArrayList extensionReflectors;
64                 ServiceDescriptionReflector serviceReflector;
65
66                 XmlReflectionImporter reflectionImporter;
67                 SoapReflectionImporter soapReflectionImporter;
68                 
69                 CodeIdentifiers portNames;
70                 
71                 #endregion // Fields
72
73                 #region Constructors
74         
75                 protected ProtocolReflector ()
76                 {
77                         defaultNamespace = WebServiceAttribute.DefaultNamespace;
78                         extensionReflectors = ExtensionManager.BuildExtensionReflectors ();
79                 }
80                 
81                 #endregion // Constructors
82
83                 #region Properties
84
85                 public Binding Binding {
86                         get { return binding; }
87                 }
88
89                 public string DefaultNamespace {
90                         get { return defaultNamespace; }
91                 }
92
93                 public MessageCollection HeaderMessages {
94                         get { return headerMessages; }  // TODO: set
95                 }
96
97                 public Message InputMessage {
98                         get { return inputMessage; }
99                 }
100
101                 public LogicalMethodInfo Method {
102                         get { return methodStubInfo.MethodInfo; }
103                 }
104
105                 public WebMethodAttribute MethodAttribute {
106                         get { return methodStubInfo.MethodAttribute; }
107                 }
108
109                 public LogicalMethodInfo[] Methods {
110                         get { return typeInfo.LogicalType.LogicalMethods; }
111                 }
112         
113                 public Operation Operation {
114                         get { return operation; }
115                 }
116
117                 public OperationBinding OperationBinding {
118                         get { return operationBinding; }
119                 }
120
121                 public Message OutputMessage {
122                         get { return outputMessage; }
123                 }
124
125                 public Port Port {
126                         get { return port; }
127                 }
128
129                 public PortType PortType {
130                         get { return portType; }
131                 }
132
133                 public abstract string ProtocolName {
134                         get; 
135                 }
136
137                 public XmlReflectionImporter ReflectionImporter 
138                 {
139                         get
140                         {
141                                 if (reflectionImporter == null) {
142                                         reflectionImporter = typeInfo.XmlImporter;
143                                         if (reflectionImporter == null)
144                                                 reflectionImporter = new XmlReflectionImporter();
145                                 }
146                                 return reflectionImporter;
147                         }
148                 }
149
150                 internal SoapReflectionImporter SoapReflectionImporter 
151                 {
152                         get
153                         {
154                                 if (soapReflectionImporter == null) {
155                                         soapReflectionImporter = typeInfo.SoapImporter;
156                                         if (soapReflectionImporter == null)
157                                                 soapReflectionImporter = new SoapReflectionImporter();
158                                 }
159                                 return soapReflectionImporter;
160                         }
161                 }
162
163                 public XmlSchemaExporter SchemaExporter {
164                         get { return schemaExporter; }
165                 }
166
167                 internal SoapSchemaExporter SoapSchemaExporter {
168                         get { return soapSchemaExporter; }
169                 }
170
171                 public XmlSchemas Schemas {
172                         get { return serviceReflector.Schemas; }
173                 }
174
175                 public Service Service {
176                         get { return service; }
177                 }
178
179                 public ServiceDescription ServiceDescription {
180                         get { return serviceDescription; }
181                 }
182
183                 public ServiceDescriptionCollection ServiceDescriptions {
184                         get { return serviceReflector.ServiceDescriptions; }
185                 }
186
187                 public Type ServiceType {
188                         get { return serviceType; }
189                 }
190
191                 public string ServiceUrl {
192                         get { return serviceUrl; }
193                 }
194                 
195                 internal MethodStubInfo MethodStubInfo {
196                         get { return methodStubInfo; }
197                 }
198                 
199                 internal TypeStubInfo TypeInfo {
200                         get { return typeInfo; }
201                 }
202
203
204                 #endregion // Properties
205
206                 #region Methods
207                 
208                 internal void Reflect (ServiceDescriptionReflector serviceReflector, Type type, string url, XmlSchemaExporter xxporter, SoapSchemaExporter sxporter)
209                 {
210                         portNames = new CodeIdentifiers ();
211                         this.serviceReflector = serviceReflector;
212                         serviceUrl = url;
213                         serviceType = type;
214                         
215                         schemaExporter = xxporter;
216                         soapSchemaExporter = sxporter;
217                         
218                         typeInfo = TypeStubManager.GetTypeStub (type, ProtocolName);
219                         
220                         ServiceDescription desc = ServiceDescriptions [typeInfo.LogicalType.WebServiceNamespace];
221                         
222                         if (desc == null)
223                         {
224                                 desc = new ServiceDescription ();
225                                 desc.TargetNamespace = typeInfo.LogicalType.WebServiceNamespace;
226                                 desc.Name = typeInfo.LogicalType.WebServiceName;
227                                 ServiceDescriptions.Add (desc);
228                         }
229                         
230                         ImportService (desc, typeInfo, url);                    
231                 }
232
233                 void ImportService (ServiceDescription desc, TypeStubInfo typeInfo, string url)
234                 {
235                         service = desc.Services [typeInfo.LogicalType.WebServiceName];
236                         if (service == null)
237                         {
238                                 service = new Service ();
239                                 service.Name = typeInfo.LogicalType.WebServiceName;
240                                 service.Documentation = typeInfo.LogicalType.Description;
241                                 desc.Services.Add (service);
242                         }
243                         
244                         foreach (BindingInfo binfo in typeInfo.Bindings)
245                                 ImportBinding (desc, service, typeInfo, url, binfo);
246                 }
247                 
248                 void ImportBinding (ServiceDescription desc, Service service, TypeStubInfo typeInfo, string url, BindingInfo binfo)
249                 {
250                         port = new Port ();
251                         port.Name = portNames.AddUnique (binfo.Name, port);
252                         bool bindingFull = true;
253
254                         if (binfo.Namespace != desc.TargetNamespace)
255                         {
256                                 if (binfo.Location == null || binfo.Location == string.Empty)
257                                 {
258                                         ServiceDescription newDesc = new ServiceDescription();
259                                         newDesc.TargetNamespace = binfo.Namespace;
260                                         newDesc.Name = binfo.Name;
261                                         bindingFull = ImportBindingContent (newDesc, typeInfo, url, binfo);
262                                         if (bindingFull) {
263                                                 int id = ServiceDescriptions.Add (newDesc);
264                                                 AddImport (desc, binfo.Namespace, GetWsdlUrl (url,id));
265                                         }
266                                 }
267                                 else {
268                                         AddImport (desc, binfo.Namespace, binfo.Location);
269                                         bindingFull = true;
270                                 }
271                         }
272                         else
273                                 bindingFull = ImportBindingContent (desc, typeInfo, url, binfo);
274                                 
275                         if (bindingFull)
276                         {
277                                 port.Binding = new XmlQualifiedName (binding.Name, binfo.Namespace);
278                                 service.Ports.Add (port);
279                         }
280                 }
281
282                 bool ImportBindingContent (ServiceDescription desc, TypeStubInfo typeInfo, string url, BindingInfo binfo)
283                 {
284                         serviceDescription = desc;
285                         
286                         // Look for an unused name
287                         
288                         int n=0;
289                         string name = binfo.Name;
290                         bool found;
291                         do
292                         {
293                                 found = false;
294                                 foreach (Binding bi in desc.Bindings)
295                                         if (bi.Name == name) { found = true; n++; name = binfo.Name+n; break; }
296                         }
297                         while (found);
298                         
299                         // Create the binding
300                         
301                         binding = new Binding ();
302                         binding.Name = name;
303                         binding.Type = new XmlQualifiedName (binding.Name, binfo.Namespace);
304                         
305                         portType = new PortType ();
306                         portType.Name = binding.Name;
307
308                         BeginClass ();
309                         
310                         foreach (MethodStubInfo method in typeInfo.Methods)
311                         {
312                                 methodStubInfo = method;
313                                 
314                                 string metBinding = ReflectMethodBinding ();
315                                 if (typeInfo.GetBinding (metBinding) != binfo) continue;
316                                 
317                                 operation = new Operation ();
318                                 operation.Name = method.OperationName;
319                                 operation.Documentation = method.MethodAttribute.Description;
320                                 
321                                 inputMessage = new Message ();
322                                 inputMessage.Name = method.Name + ProtocolName + "In";
323                                 ServiceDescription.Messages.Add (inputMessage);
324                                 
325                                 outputMessage = new Message ();
326                                 outputMessage.Name = method.Name + ProtocolName + "Out";
327                                 ServiceDescription.Messages.Add (outputMessage);
328
329                                 OperationInput inOp = new OperationInput ();
330                                 if (method.Name != method.OperationName) inOp.Name = method.Name;
331                                 Operation.Messages.Add (inOp);
332                                 inOp.Message = new XmlQualifiedName (inputMessage.Name, ServiceDescription.TargetNamespace);
333                                 
334                                 OperationOutput outOp = new OperationOutput ();
335                                 if (method.Name != method.OperationName) outOp.Name = method.Name;
336                                 Operation.Messages.Add (outOp);
337                                 outOp.Message = new XmlQualifiedName (outputMessage.Name, ServiceDescription.TargetNamespace);
338                         
339                                 portType.Operations.Add (operation);
340                                 ImportOperationBinding ();
341                                 
342                                 ReflectMethod ();
343                                 
344                                 foreach (SoapExtensionReflector reflector in extensionReflectors)
345                                 {
346                                         reflector.ReflectionContext = this;
347                                         reflector.ReflectMethod ();
348                                 }
349                         }
350                         
351                         EndClass ();
352                         
353                         if (portType.Operations.Count > 0)
354                         {
355                                 desc.Bindings.Add (binding);
356                                 desc.PortTypes.Add (portType);
357                                 return true;
358                         }
359                         else
360                                 return false;
361                 }
362
363                 void ImportOperationBinding ()
364                 {
365                         operationBinding = new OperationBinding ();
366                         operationBinding.Name = methodStubInfo.OperationName;
367                         
368                         InputBinding inOp = new InputBinding ();
369                         operationBinding.Input = inOp;
370                         
371                         OutputBinding outOp = new OutputBinding ();
372                         operationBinding.Output = outOp;
373                         
374                         if (methodStubInfo.OperationName != methodStubInfo.Name)
375                                 inOp.Name = outOp.Name = methodStubInfo.Name;
376                         
377                         binding.Operations.Add (operationBinding);
378                 }
379                 
380                 internal static void AddImport (ServiceDescription desc, string ns, string location)
381                 {
382                         Import im = new Import();
383                         im.Namespace = ns;
384                         im.Location = location;
385                         desc.Imports.Add (im);
386                 }
387                 
388                 string GetWsdlUrl (string baseUrl, int id)
389                 {
390                         return baseUrl + "?wsdl=" + id;
391                 }
392                 
393                 protected virtual void BeginClass ()
394                 {
395                 }
396
397                 protected virtual void EndClass ()
398                 {
399                 }
400
401                 public ServiceDescription GetServiceDescription (string ns)
402                 {
403                         return ServiceDescriptions [ns];
404                 }
405
406                 protected abstract bool ReflectMethod ();
407
408                 protected virtual string ReflectMethodBinding ()
409                 {
410                         return null;
411                 }
412
413                 #endregion
414         }
415 }