2006-11-02 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / SoapProtocolReflector.cs
1 // 
2 // System.Web.Services.Description.SoapProtocolReflector.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.Schema;
36 using System.Xml;
37
38 namespace System.Web.Services.Description {
39
40         internal class SoapProtocolReflector : ProtocolReflector 
41         {
42                 #region Fields
43
44                 internal const string EncodingNamespace = "http://schemas.xmlsoap.org/soap/encoding/";
45                 SoapBinding soapBinding;
46
47                 #endregion // Fields
48
49                 #region Constructors
50
51                 public SoapProtocolReflector ()
52                 {
53                 }
54                 
55                 #endregion // Constructors
56
57                 #region Properties
58
59                 public override string ProtocolName {
60                         get { return "Soap"; }
61                 }
62
63                 #endregion // Properties
64
65                 #region Methods
66
67                 protected override void BeginClass ()
68                 {
69                         SoapBinding sb = new SoapBinding ();
70                         sb.Transport = SoapBinding.HttpTransport;
71                         sb.Style = ((SoapTypeStubInfo)TypeInfo).SoapBindingStyle;
72                         Binding.Extensions.Add (sb);
73
74                         SoapAddressBinding abind = new SoapAddressBinding ();
75                         abind.Location = ServiceUrl;
76                         Port.Extensions.Add (abind);
77                 }
78
79                 protected override void EndClass ()
80                 {
81                 }
82
83                 protected override bool ReflectMethod ()
84                 {
85                         SoapOperationBinding sob = new SoapOperationBinding();
86                         SoapMethodStubInfo method = (SoapMethodStubInfo) MethodStubInfo;
87                         
88                         sob.SoapAction = method.Action;
89                         sob.Style = method.SoapBindingStyle;
90                         OperationBinding.Extensions.Add (sob);
91                         
92                         ImportMessage (method.InputMembersMapping, InputMessage);
93                         ImportMessage (method.OutputMembersMapping, OutputMessage);
94                                 
95                         AddOperationMsgBindings (method, OperationBinding.Input);
96                         AddOperationMsgBindings (method, OperationBinding.Output);
97
98                         foreach (HeaderInfo hf in method.Headers)
99                         {
100                                 if (hf.IsUnknownHeader) continue;
101                                 
102                                 Message msg = new Message ();
103                                 msg.Name = Operation.Name + hf.HeaderType.Name;
104                                 MessagePart part = new MessagePart ();
105                                 part.Name = hf.HeaderType.Name;
106                                 msg.Parts.Add (part);
107                                 ServiceDescription.Messages.Add (msg);
108
109                                 SoapHeaderBinding hb = new SoapHeaderBinding ();
110                                 hb.Message = new XmlQualifiedName (msg.Name, ServiceDescription.TargetNamespace);
111                                 hb.Part = part.Name;
112                                 hb.Use = method.Use;
113                                 
114                                 if (method.Use == SoapBindingUse.Literal)
115                                 {
116                                         // MS.NET reflects header classes in a weird way. The root element
117                                         // name is the CLR class name unless it is specified in an XmlRootAttribute.
118                                         // The usual is to use the xml type name by default, but not in this case.
119                                 
120                                         XmlRootAttribute root;
121                                         XmlAttributes ats = new XmlAttributes (hf.HeaderType);
122                                         if (ats.XmlRoot != null) root = ats.XmlRoot;
123                                         else root = new XmlRootAttribute (hf.HeaderType.Name);
124                                         
125                                         if (root.Namespace == null) root.Namespace = TypeInfo.LogicalType.GetWebServiceLiteralNamespace (ServiceDescription.TargetNamespace);
126                                         if (root.ElementName == null) root.ElementName = hf.HeaderType.Name;
127                                         
128                                         XmlTypeMapping mapping = ReflectionImporter.ImportTypeMapping (hf.HeaderType, root);
129                                         part.Element = new XmlQualifiedName (mapping.ElementName, mapping.Namespace);
130                                         SchemaExporter.ExportTypeMapping (mapping);
131                                 }
132                                 else
133                                 {
134                                         XmlTypeMapping mapping = SoapReflectionImporter.ImportTypeMapping (hf.HeaderType, TypeInfo.LogicalType.GetWebServiceEncodedNamespace (ServiceDescription.TargetNamespace));
135                                         part.Type = new XmlQualifiedName (mapping.ElementName, mapping.Namespace);
136                                         SoapSchemaExporter.ExportTypeMapping (mapping);
137                                         hb.Encoding = EncodingNamespace;
138                                 }
139
140                                 if ((hf.Direction & SoapHeaderDirection.Out) != 0)
141                                         OperationBinding.Output.Extensions.Add (hb);
142                                 if ((hf.Direction & SoapHeaderDirection.In) != 0)
143                                         OperationBinding.Input.Extensions.Add (hb);
144                         }
145                         
146                         return true;
147                 }
148
149                 void AddOperationMsgBindings (SoapMethodStubInfo method, MessageBinding msg)
150                 {
151                         SoapBodyBinding sbbo = new SoapBodyBinding();
152                         msg.Extensions.Add (sbbo);
153                         sbbo.Use = method.Use;
154                         if (method.Use == SoapBindingUse.Encoded)
155                         {
156                                 sbbo.Namespace = ServiceDescription.TargetNamespace;
157                                 sbbo.Encoding = EncodingNamespace;
158                         }
159                 }
160                 
161                 void ImportMessage (XmlMembersMapping members, Message msg)
162                 {
163                         SoapMethodStubInfo method = (SoapMethodStubInfo) MethodStubInfo;
164                         bool needsEnclosingElement = (method.ParameterStyle == SoapParameterStyle.Wrapped && 
165                                                                                         method.SoapBindingStyle == SoapBindingStyle.Document);
166
167                         if (needsEnclosingElement)
168                         {
169                                 MessagePart part = new MessagePart ();
170                                 part.Name = "parameters";
171                                 XmlQualifiedName qname = new XmlQualifiedName (members.ElementName, members.Namespace);
172                                 if (method.Use == SoapBindingUse.Literal) part.Element = qname;
173                                 else part.Type = qname;
174                                 msg.Parts.Add (part);
175                         }
176                         else
177                         {
178                                 for (int n=0; n<members.Count; n++)
179                                 {
180                                         MessagePart part = new MessagePart ();
181                                         part.Name = members[n].MemberName;
182                                         
183                                         if (method.Use == SoapBindingUse.Literal) {
184                                                 if (members[n].Any)
185                                                         part.Type = new XmlQualifiedName ("any", members[n].Namespace);
186                                                 else
187                                                         part.Element = new XmlQualifiedName (members[n].ElementName, members[n].Namespace);
188                                         }
189                                         else {
190                                                 string namesp = members[n].TypeNamespace;
191                                                 if (namesp == "") namesp = members[n].Namespace;
192                                                 part.Type = new XmlQualifiedName (members[n].TypeName, namesp);
193                                         }
194                                         msg.Parts.Add (part);
195                                 }
196                         }
197                         
198                         
199                         if (method.Use == SoapBindingUse.Literal)
200                                 SchemaExporter.ExportMembersMapping (members);
201                         else
202                                 SoapSchemaExporter.ExportMembersMapping (members, needsEnclosingElement);
203                 }
204
205                 protected override string ReflectMethodBinding ()
206                 {
207                         return ((SoapMethodStubInfo)MethodStubInfo).Binding;
208                 }
209
210                 #endregion
211         }
212 }