2010-04-15 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Web.Services / System.Web.Services.Description / ProtocolReflector.cs
blob9dadfe00ce289d60aaa0d3f41e9775b8f1ce1488
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 //
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.
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;
39 namespace System.Web.Services.Description {
40 public abstract class ProtocolReflector {
42 #region Fields
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;
66 XmlReflectionImporter reflectionImporter;
67 SoapReflectionImporter soapReflectionImporter;
69 CodeIdentifiers portNames;
71 #endregion // Fields
73 #region Constructors
75 protected ProtocolReflector ()
77 defaultNamespace = WebServiceAttribute.DefaultNamespace;
78 extensionReflectors = ExtensionManager.BuildExtensionReflectors ();
81 #endregion // Constructors
83 #region Properties
85 internal ServiceDescriptionReflector Parent {
86 get { return serviceReflector; }
89 public Binding Binding {
90 get { return binding; }
93 public string DefaultNamespace {
94 get { return defaultNamespace; }
97 public MessageCollection HeaderMessages {
98 get { return headerMessages; } // TODO: set
101 public Message InputMessage {
102 get { return inputMessage; }
105 public LogicalMethodInfo Method {
106 get { return methodStubInfo.MethodInfo; }
109 public WebMethodAttribute MethodAttribute {
110 get { return methodStubInfo.MethodAttribute; }
113 public LogicalMethodInfo[] Methods {
114 get { return typeInfo.LogicalType.LogicalMethods; }
117 public Operation Operation {
118 get { return operation; }
121 public OperationBinding OperationBinding {
122 get { return operationBinding; }
125 public Message OutputMessage {
126 get { return outputMessage; }
129 public Port Port {
130 get { return port; }
133 public PortType PortType {
134 get { return portType; }
137 public abstract string ProtocolName {
138 get;
141 public XmlReflectionImporter ReflectionImporter
145 if (reflectionImporter == null) {
146 reflectionImporter = typeInfo.XmlImporter;
147 if (reflectionImporter == null)
148 reflectionImporter = new XmlReflectionImporter();
150 return reflectionImporter;
154 internal SoapReflectionImporter SoapReflectionImporter
158 if (soapReflectionImporter == null) {
159 soapReflectionImporter = typeInfo.SoapImporter;
160 if (soapReflectionImporter == null)
161 soapReflectionImporter = new SoapReflectionImporter();
163 return soapReflectionImporter;
167 public XmlSchemaExporter SchemaExporter {
168 get { return schemaExporter; }
171 internal SoapSchemaExporter SoapSchemaExporter {
172 get { return soapSchemaExporter; }
175 public XmlSchemas Schemas {
176 get { return serviceReflector.Schemas; }
179 public Service Service {
180 get { return service; }
183 public ServiceDescription ServiceDescription {
184 get { return serviceDescription; }
187 public ServiceDescriptionCollection ServiceDescriptions {
188 get { return serviceReflector.ServiceDescriptions; }
191 public Type ServiceType {
192 get { return serviceType; }
195 public string ServiceUrl {
196 get { return serviceUrl; }
199 internal MethodStubInfo MethodStubInfo {
200 get { return methodStubInfo; }
203 internal TypeStubInfo TypeInfo {
204 get { return typeInfo; }
207 #endregion // Properties
209 #region Methods
211 internal void Reflect (ServiceDescriptionReflector serviceReflector, Type type, string url, XmlSchemaExporter xxporter, SoapSchemaExporter sxporter)
213 portNames = new CodeIdentifiers ();
214 this.serviceReflector = serviceReflector;
215 serviceUrl = url;
216 serviceType = type;
218 schemaExporter = xxporter;
219 soapSchemaExporter = sxporter;
221 typeInfo = TypeStubManager.GetTypeStub (type, ProtocolName);
223 ServiceDescription desc = ServiceDescriptions [typeInfo.LogicalType.WebServiceNamespace];
225 if (desc == null)
227 desc = new ServiceDescription ();
228 desc.TargetNamespace = typeInfo.LogicalType.WebServiceNamespace;
229 desc.Name = typeInfo.LogicalType.WebServiceName;
230 ServiceDescriptions.Add (desc);
233 ImportService (desc, typeInfo, url);
236 void ImportService (ServiceDescription desc, TypeStubInfo typeInfo, string url)
238 service = desc.Services [typeInfo.LogicalType.WebServiceName];
239 if (service == null)
241 service = new Service ();
242 service.Name = typeInfo.LogicalType.WebServiceName;
243 service.Documentation = typeInfo.LogicalType.Description;
244 desc.Services.Add (service);
247 foreach (BindingInfo binfo in typeInfo.Bindings)
248 ImportBinding (desc, service, typeInfo, url, binfo);
251 void ImportBinding (ServiceDescription desc, Service service, TypeStubInfo typeInfo, string url, BindingInfo binfo)
253 port = new Port ();
254 port.Name = portNames.AddUnique (binfo.Name, port);
255 bool bindingFull = true;
257 if (binfo.Namespace != desc.TargetNamespace)
259 if (binfo.Location == null || binfo.Location == string.Empty)
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));
270 else {
271 AddImport (desc, binfo.Namespace, binfo.Location);
272 bindingFull = true;
275 else
276 bindingFull = ImportBindingContent (desc, typeInfo, url, binfo);
278 if (bindingFull)
280 port.Binding = new XmlQualifiedName (binding.Name, binfo.Namespace);
282 int n = 0;
283 string name = binfo.Name;
284 bool found;
285 do {
287 found = false;
288 foreach (Port p in service.Ports)
289 if (p.Name == name) { found = true; n++; name = binfo.Name + n; break; }
291 while (found);
292 port.Name = name;
293 service.Ports.Add (port);
296 #if NET_2_0
297 if (binfo.WebServiceBindingAttribute != null && binfo.WebServiceBindingAttribute.ConformsTo != WsiProfiles.None && String.IsNullOrEmpty (binfo.WebServiceBindingAttribute.Name)) {
298 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
299 desc.Types.Schemas.Add (Schemas);
300 ServiceDescriptionCollection col = new ServiceDescriptionCollection ();
301 col.Add (desc);
302 ConformanceCheckContext ctx = new ConformanceCheckContext (col, violations);
303 ctx.ServiceDescription = desc;
304 ConformanceChecker[] checkers = WebServicesInteroperability.GetCheckers (binfo.WebServiceBindingAttribute.ConformsTo);
305 foreach (ConformanceChecker checker in checkers) {
306 ctx.Checker = checker;
307 WebServicesInteroperability.Check (ctx, checker, binding);
308 if (violations.Count > 0)
309 throw new InvalidOperationException (violations [0].ToString ());
312 #endif
315 bool ImportBindingContent (ServiceDescription desc, TypeStubInfo typeInfo, string url, BindingInfo binfo)
317 serviceDescription = desc;
319 // Look for an unused name
321 int n=0;
322 string name = binfo.Name;
323 bool found;
326 found = false;
327 foreach (Binding bi in desc.Bindings)
328 if (bi.Name == name) { found = true; n++; name = binfo.Name+n; break; }
330 while (found);
332 // Create the binding
334 binding = new Binding ();
335 binding.Name = name;
336 binding.Type = new XmlQualifiedName (binding.Name, binfo.Namespace);
337 #if NET_2_0
338 if (binfo.WebServiceBindingAttribute != null && binfo.WebServiceBindingAttribute.EmitConformanceClaims) {
339 XmlDocument doc = new XmlDocument ();
340 XmlElement docElement = doc.CreateElement ("wsdl", "documentation", "http://schemas.xmlsoap.org/wsdl/");
341 XmlElement claimsElement = doc.CreateElement ("wsi", "Claim", "http://ws-i.org/schemas/conformanceClaim/");
342 claimsElement.Attributes.Append (doc.CreateAttribute ("conformsTo")).Value = "http://ws-i.org/profiles/basic/1.1";
343 docElement.AppendChild (claimsElement);
344 binding.DocumentationElement = docElement;
346 #endif
348 portType = new PortType ();
349 portType.Name = binding.Name;
351 BeginClass ();
353 foreach (SoapExtensionReflector reflector in extensionReflectors)
355 reflector.ReflectionContext = this;
356 reflector.ReflectDescription ();
359 foreach (MethodStubInfo method in typeInfo.Methods)
361 methodStubInfo = method;
363 string metBinding = ReflectMethodBinding ();
364 if (typeInfo.GetBinding (metBinding) != binfo) continue;
366 operation = new Operation ();
367 operation.Name = method.OperationName;
368 operation.Documentation = method.MethodAttribute.Description;
370 // FIXME: SOAP 1.1 and SOAP 1.2 should share
371 // the same message definitions.
373 inputMessage = new Message ();
374 inputMessage.Name = method.Name + ProtocolName + "In";
375 ServiceDescription.Messages.Add (inputMessage);
377 outputMessage = new Message ();
378 outputMessage.Name = method.Name + ProtocolName + "Out";
379 ServiceDescription.Messages.Add (outputMessage);
381 OperationInput inOp = new OperationInput ();
382 if (method.Name != method.OperationName) inOp.Name = method.Name;
383 Operation.Messages.Add (inOp);
384 inOp.Message = new XmlQualifiedName (inputMessage.Name, ServiceDescription.TargetNamespace);
386 OperationOutput outOp = new OperationOutput ();
387 if (method.Name != method.OperationName) outOp.Name = method.Name;
388 Operation.Messages.Add (outOp);
389 outOp.Message = new XmlQualifiedName (outputMessage.Name, ServiceDescription.TargetNamespace);
391 portType.Operations.Add (operation);
392 ImportOperationBinding ();
394 if (!ReflectMethod ()) {
395 #if NET_2_0
396 // (It is somewhat hacky) If we don't
397 // add input/output Messages, update
398 // portType/input/@message and
399 // porttype/output/@message.
400 Message dupIn = Parent.MappedMessagesIn [method.MethodInfo];
401 ServiceDescription.Messages.Remove (inputMessage);
402 inOp.Message = new XmlQualifiedName (dupIn.Name, ServiceDescription.TargetNamespace);
403 Message dupOut = Parent.MappedMessagesOut [method.MethodInfo];
404 ServiceDescription.Messages.Remove (outputMessage);
405 outOp.Message = new XmlQualifiedName (dupOut.Name, ServiceDescription.TargetNamespace);
406 #endif
409 foreach (SoapExtensionReflector reflector in extensionReflectors)
411 reflector.ReflectionContext = this;
412 reflector.ReflectMethod ();
416 EndClass ();
418 if (portType.Operations.Count > 0)
420 desc.Bindings.Add (binding);
421 desc.PortTypes.Add (portType);
422 return true;
424 else
425 return false;
428 void ImportOperationBinding ()
430 operationBinding = new OperationBinding ();
431 operationBinding.Name = methodStubInfo.OperationName;
433 InputBinding inOp = new InputBinding ();
434 operationBinding.Input = inOp;
436 OutputBinding outOp = new OutputBinding ();
437 operationBinding.Output = outOp;
439 if (methodStubInfo.OperationName != methodStubInfo.Name)
440 inOp.Name = outOp.Name = methodStubInfo.Name;
442 binding.Operations.Add (operationBinding);
445 internal static void AddImport (ServiceDescription desc, string ns, string location)
447 Import im = new Import();
448 im.Namespace = ns;
449 im.Location = location;
450 desc.Imports.Add (im);
453 string GetWsdlUrl (string baseUrl, int id)
455 return baseUrl + "?wsdl=" + id;
458 protected virtual void BeginClass ()
462 protected virtual void EndClass ()
466 public ServiceDescription GetServiceDescription (string ns)
468 return ServiceDescriptions [ns];
471 protected abstract bool ReflectMethod ();
473 protected virtual string ReflectMethodBinding ()
475 return null;
478 #if NET_2_0
479 [MonoNotSupported("Not Implemented")]
480 protected virtual void ReflectDescription ()
482 throw new NotImplementedException ();
484 #endif
486 #endregion