[corlib] Remove System.Core security types
[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                 internal ServiceDescriptionReflector Parent {
86                         get { return serviceReflector; }
87                 }
88
89                 public Binding Binding {
90                         get { return binding; }
91                 }
92
93                 public string DefaultNamespace {
94                         get { return defaultNamespace; }
95                 }
96
97                 public MessageCollection HeaderMessages {
98                         get { return headerMessages; }  // TODO: set
99                 }
100
101                 public Message InputMessage {
102                         get { return inputMessage; }
103                 }
104
105                 public LogicalMethodInfo Method {
106                         get { return methodStubInfo.MethodInfo; }
107                 }
108
109                 public WebMethodAttribute MethodAttribute {
110                         get { return methodStubInfo.MethodAttribute; }
111                 }
112
113                 public LogicalMethodInfo[] Methods {
114                         get { return typeInfo.LogicalType.LogicalMethods; }
115                 }
116         
117                 public Operation Operation {
118                         get { return operation; }
119                 }
120
121                 public OperationBinding OperationBinding {
122                         get { return operationBinding; }
123                 }
124
125                 public Message OutputMessage {
126                         get { return outputMessage; }
127                 }
128
129                 public Port Port {
130                         get { return port; }
131                 }
132
133                 public PortType PortType {
134                         get { return portType; }
135                 }
136
137                 public abstract string ProtocolName {
138                         get; 
139                 }
140
141                 public XmlReflectionImporter ReflectionImporter 
142                 {
143                         get
144                         {
145                                 if (reflectionImporter == null) {
146                                         reflectionImporter = typeInfo.XmlImporter;
147                                         if (reflectionImporter == null)
148                                                 reflectionImporter = new XmlReflectionImporter();
149                                 }
150                                 return reflectionImporter;
151                         }
152                 }
153
154                 internal SoapReflectionImporter SoapReflectionImporter 
155                 {
156                         get
157                         {
158                                 if (soapReflectionImporter == null) {
159                                         soapReflectionImporter = typeInfo.SoapImporter;
160                                         if (soapReflectionImporter == null)
161                                                 soapReflectionImporter = new SoapReflectionImporter();
162                                 }
163                                 return soapReflectionImporter;
164                         }
165                 }
166
167                 public XmlSchemaExporter SchemaExporter {
168                         get { return schemaExporter; }
169                 }
170
171                 internal SoapSchemaExporter SoapSchemaExporter {
172                         get { return soapSchemaExporter; }
173                 }
174
175                 public XmlSchemas Schemas {
176                         get { return serviceReflector.Schemas; }
177                 }
178
179                 public Service Service {
180                         get { return service; }
181                 }
182
183                 public ServiceDescription ServiceDescription {
184                         get { return serviceDescription; }
185                 }
186
187                 public ServiceDescriptionCollection ServiceDescriptions {
188                         get { return serviceReflector.ServiceDescriptions; }
189                 }
190
191                 public Type ServiceType {
192                         get { return serviceType; }
193                 }
194
195                 public string ServiceUrl {
196                         get { return serviceUrl; }
197                 }
198                 
199                 internal MethodStubInfo MethodStubInfo {
200                         get { return methodStubInfo; }
201                 }
202                 
203                 internal TypeStubInfo TypeInfo {
204                         get { return typeInfo; }
205                 }
206
207                 #endregion // Properties
208
209                 #region Methods
210                 
211                 internal void Reflect (ServiceDescriptionReflector serviceReflector, Type type, string url, XmlSchemaExporter xxporter, SoapSchemaExporter sxporter)
212                 {
213                         portNames = new CodeIdentifiers ();
214                         this.serviceReflector = serviceReflector;
215                         serviceUrl = url;
216                         serviceType = type;
217                         
218                         schemaExporter = xxporter;
219                         soapSchemaExporter = sxporter;
220                         
221                         typeInfo = TypeStubManager.GetTypeStub (type, ProtocolName);
222                         
223                         ServiceDescription desc = ServiceDescriptions [typeInfo.LogicalType.WebServiceNamespace];
224                         
225                         if (desc == null)
226                         {
227                                 desc = new ServiceDescription ();
228                                 desc.TargetNamespace = typeInfo.LogicalType.WebServiceNamespace;
229                                 desc.Name = typeInfo.LogicalType.WebServiceName;
230                                 ServiceDescriptions.Add (desc);
231                         }
232                         
233                         ImportService (desc, typeInfo, url);                    
234                 }
235
236                 void ImportService (ServiceDescription desc, TypeStubInfo typeInfo, string url)
237                 {
238                         service = desc.Services [typeInfo.LogicalType.WebServiceName];
239                         if (service == null)
240                         {
241                                 service = new Service ();
242                                 service.Name = typeInfo.LogicalType.WebServiceName;
243                                 service.Documentation = typeInfo.LogicalType.Description;
244                                 desc.Services.Add (service);
245                         }
246                         
247                         foreach (BindingInfo binfo in typeInfo.Bindings)
248                                 ImportBinding (desc, service, typeInfo, url, binfo);
249                 }
250                 
251                 void ImportBinding (ServiceDescription desc, Service service, TypeStubInfo typeInfo, string url, BindingInfo binfo)
252                 {
253                         port = new Port ();
254                         port.Name = portNames.AddUnique (binfo.Name, port);
255                         bool bindingFull = true;
256
257                         if (binfo.Namespace != desc.TargetNamespace)
258                         {
259                                 if (binfo.Location == null || binfo.Location == string.Empty)
260                                 {
261                                         ServiceDescription newDesc = new ServiceDescription();
262                                         newDesc.TargetNamespace = binfo.Namespace;
263                                         newDesc.Name = binfo.Name;
264                                         bindingFull = ImportBindingContent (newDesc, typeInfo, url, binfo);
265                                         if (bindingFull) {
266                                                 int id = ServiceDescriptions.Add (newDesc);
267                                                 AddImport (desc, binfo.Namespace, GetWsdlUrl (url,id));
268                                         }
269                                 }
270                                 else {
271                                         AddImport (desc, binfo.Namespace, binfo.Location);
272                                         bindingFull = true;
273                                 }
274                         }
275                         else
276                                 bindingFull = ImportBindingContent (desc, typeInfo, url, binfo);
277                                 
278                         if (bindingFull)
279                         {
280                                 port.Binding = new XmlQualifiedName (binding.Name, binfo.Namespace);
281                                 
282                                 int n = 0;
283                                 string name = binfo.Name; 
284                                 bool found;
285                                 do {
286
287                                         found = false;
288                                         foreach (Port p in service.Ports)
289                                                 if (p.Name == name) { found = true; n++; name = binfo.Name + n; break; }
290                                 }
291                                 while (found);
292                                 port.Name = name;
293                                 service.Ports.Add (port);
294                         }
295
296                         if (binfo.WebServiceBindingAttribute != null && binfo.WebServiceBindingAttribute.ConformsTo != WsiProfiles.None && String.IsNullOrEmpty (binfo.WebServiceBindingAttribute.Name)) {
297                                 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
298                                 desc.Types.Schemas.Add (Schemas);
299                                 ServiceDescriptionCollection col = new ServiceDescriptionCollection ();
300                                 col.Add (desc);
301                                 ConformanceCheckContext ctx = new ConformanceCheckContext (col, violations);
302                                 ctx.ServiceDescription = desc;
303                                 ConformanceChecker[] checkers = WebServicesInteroperability.GetCheckers (binfo.WebServiceBindingAttribute.ConformsTo);
304                                 foreach (ConformanceChecker checker in checkers) {
305                                         ctx.Checker = checker;
306                                         WebServicesInteroperability.Check (ctx, checker, binding);
307                                         if (violations.Count > 0)
308                                                 throw new InvalidOperationException (violations [0].ToString ());
309                                 }
310                         }
311                 }
312
313                 bool ImportBindingContent (ServiceDescription desc, TypeStubInfo typeInfo, string url, BindingInfo binfo)
314                 {
315                         serviceDescription = desc;
316                         
317                         // Look for an unused name
318                         
319                         int n=0;
320                         string name = binfo.Name;
321                         bool found;
322                         do
323                         {
324                                 found = false;
325                                 foreach (Binding bi in desc.Bindings)
326                                         if (bi.Name == name) { found = true; n++; name = binfo.Name+n; break; }
327                         }
328                         while (found);
329                         
330                         // Create the binding
331                         
332                         binding = new Binding ();
333                         binding.Name = name;
334                         binding.Type = new XmlQualifiedName (binding.Name, binfo.Namespace);
335                         if (binfo.WebServiceBindingAttribute != null && binfo.WebServiceBindingAttribute.EmitConformanceClaims) {
336                                 XmlDocument doc = new XmlDocument ();
337                                 XmlElement docElement = doc.CreateElement ("wsdl", "documentation", "http://schemas.xmlsoap.org/wsdl/");
338                                 XmlElement claimsElement = doc.CreateElement ("wsi", "Claim", "http://ws-i.org/schemas/conformanceClaim/");
339                                 claimsElement.Attributes.Append (doc.CreateAttribute ("conformsTo")).Value = "http://ws-i.org/profiles/basic/1.1";
340                                 docElement.AppendChild (claimsElement);
341                                 binding.DocumentationElement = docElement;
342                         }
343                         
344                         portType = new PortType ();
345                         portType.Name = binding.Name;
346
347                         BeginClass ();
348
349                         foreach (SoapExtensionReflector reflector in extensionReflectors)
350                         {
351                                 reflector.ReflectionContext = this;
352                                 reflector.ReflectDescription ();
353                         }
354
355                         foreach (MethodStubInfo method in typeInfo.Methods)
356                         {
357                                 methodStubInfo = method;
358                                 
359                                 string metBinding = ReflectMethodBinding ();
360                                 if (typeInfo.GetBinding (metBinding) != binfo) continue;
361                                 
362                                 operation = new Operation ();
363                                 operation.Name = method.OperationName;
364                                 operation.Documentation = method.MethodAttribute.Description;
365
366                                 // FIXME: SOAP 1.1 and SOAP 1.2 should share
367                                 // the same message definitions.
368
369                                 inputMessage = new Message ();
370                                 inputMessage.Name = method.Name + ProtocolName + "In";
371                                 ServiceDescription.Messages.Add (inputMessage);
372                                 
373                                 outputMessage = new Message ();
374                                 outputMessage.Name = method.Name + ProtocolName + "Out";
375                                 ServiceDescription.Messages.Add (outputMessage);
376
377                                 OperationInput inOp = new OperationInput ();
378                                 if (method.Name != method.OperationName) inOp.Name = method.Name;
379                                 Operation.Messages.Add (inOp);
380                                 inOp.Message = new XmlQualifiedName (inputMessage.Name, ServiceDescription.TargetNamespace);
381                                 
382                                 OperationOutput outOp = new OperationOutput ();
383                                 if (method.Name != method.OperationName) outOp.Name = method.Name;
384                                 Operation.Messages.Add (outOp);
385                                 outOp.Message = new XmlQualifiedName (outputMessage.Name, ServiceDescription.TargetNamespace);
386                         
387                                 portType.Operations.Add (operation);
388                                 ImportOperationBinding ();
389                                 
390                                 if (!ReflectMethod ()) {
391                                         // (It is somewhat hacky) If we don't
392                                         // add input/output Messages, update
393                                         // portType/input/@message and
394                                         // porttype/output/@message.
395                                         Message dupIn = Parent.MappedMessagesIn [method.MethodInfo];
396                                         ServiceDescription.Messages.Remove (inputMessage);
397                                         inOp.Message = new XmlQualifiedName (dupIn.Name, ServiceDescription.TargetNamespace);
398                                         Message dupOut = Parent.MappedMessagesOut [method.MethodInfo];
399                                         ServiceDescription.Messages.Remove (outputMessage);
400                                         outOp.Message = new XmlQualifiedName (dupOut.Name, ServiceDescription.TargetNamespace);
401                                 }
402
403                                 foreach (SoapExtensionReflector reflector in extensionReflectors)
404                                 {
405                                         reflector.ReflectionContext = this;
406                                         reflector.ReflectMethod ();
407                                 }
408                         }
409                         
410                         EndClass ();
411                         
412                         if (portType.Operations.Count > 0)
413                         {
414                                 desc.Bindings.Add (binding);
415                                 desc.PortTypes.Add (portType);
416                                 return true;
417                         }
418                         else
419                                 return false;
420                 }
421
422                 void ImportOperationBinding ()
423                 {
424                         operationBinding = new OperationBinding ();
425                         operationBinding.Name = methodStubInfo.OperationName;
426                         
427                         InputBinding inOp = new InputBinding ();
428                         operationBinding.Input = inOp;
429                         
430                         OutputBinding outOp = new OutputBinding ();
431                         operationBinding.Output = outOp;
432                         
433                         if (methodStubInfo.OperationName != methodStubInfo.Name)
434                                 inOp.Name = outOp.Name = methodStubInfo.Name;
435                         
436                         binding.Operations.Add (operationBinding);
437                 }
438                 
439                 internal static void AddImport (ServiceDescription desc, string ns, string location)
440                 {
441                         Import im = new Import();
442                         im.Namespace = ns;
443                         im.Location = location;
444                         desc.Imports.Add (im);
445                 }
446                 
447                 string GetWsdlUrl (string baseUrl, int id)
448                 {
449                         return baseUrl + "?wsdl=" + id;
450                 }
451                 
452                 protected virtual void BeginClass ()
453                 {
454                 }
455
456                 protected virtual void EndClass ()
457                 {
458                 }
459
460                 public ServiceDescription GetServiceDescription (string ns)
461                 {
462                         return ServiceDescriptions [ns];
463                 }
464
465                 protected abstract bool ReflectMethod ();
466
467                 protected virtual string ReflectMethodBinding ()
468                 {
469                         return null;
470                 }
471
472                 [MonoNotSupported("Not Implemented")]
473                 protected virtual void ReflectDescription () 
474                 {
475                         throw new NotImplementedException ();
476                 }
477
478                 #endregion
479         }
480 }