* HttpSimpleProtocolReflector.cs, ProtocolReflector.cs:
[mono.git] / mcs / class / System.Web.Services / System.Web.Services.Description / ProtocolImporter.cs
1 // 
2 // System.Web.Services.Description.ProtocolImporter.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 using System;
12 using System.CodeDom;
13 using System.Web.Services;
14 using System.Web.Services.Protocols;
15 using System.Xml.Serialization;
16 using System.Xml;
17 using System.Collections;
18 using System.Configuration;
19
20 namespace System.Web.Services.Description {
21         public abstract class ProtocolImporter {
22
23                 #region Fields
24
25                 Binding binding;
26                 string className;
27                 CodeIdentifiers classNames;
28                 CodeNamespace codeNamespace;
29                 CodeCompileUnit codeCompileUnit;
30                 CodeTypeDeclaration codeTypeDeclaration;
31                 Message inputMessage;
32                 string methodName;
33                 Operation operation;
34                 OperationBinding operationBinding;
35                 Message outputMessage;          
36                 Port port;
37                 PortType portType;
38                 string protocolName;
39                 Service service;
40                 ServiceDescriptionImportWarnings warnings = (ServiceDescriptionImportWarnings)0;        
41                 ServiceDescriptionImporter descriptionImporter;
42                 ImportInfo iinfo;
43
44                 #endregion // Fields
45
46                 #region Constructors
47         
48                 protected ProtocolImporter ()
49                 {
50                 }
51                 
52                 #endregion // Constructors
53
54                 #region Properties
55
56                 [MonoTODO]
57                 public XmlSchemas AbstractSchemas {
58                         get { return descriptionImporter.Schemas; }
59                 }
60
61                 public Binding Binding {
62                         get { return binding; }
63                 }
64
65                 public string ClassName {
66                         get { return className; }
67                 }
68
69                 public CodeIdentifiers ClassNames {
70                         get { return classNames; }
71                 }
72
73                 public CodeNamespace CodeNamespace {
74                         get { return codeNamespace; }
75                 }
76
77                 public CodeTypeDeclaration CodeTypeDeclaration {
78                         get { return codeTypeDeclaration; }
79                 }
80
81                 [MonoTODO]
82                 public XmlSchemas ConcreteSchemas {
83                         get { return descriptionImporter.Schemas; }
84                 }
85
86                 public Message InputMessage {
87                         get { return inputMessage; }
88                 }
89
90                 public string MethodName {
91                         get { return methodName; }
92                 }
93
94                 public Operation Operation {
95                         get { return operation; }
96                 }
97
98                 public OperationBinding OperationBinding {
99                         get { return operationBinding; }
100                 }
101
102                 public Message OutputMessage {
103                         get { return outputMessage; }
104                 }
105
106                 public Port Port {
107                         get { return port; }
108                 }
109
110                 public PortType PortType {
111                         get { return portType; }
112                 }
113
114                 public abstract string ProtocolName {
115                         get; 
116                 }
117
118                 public XmlSchemas Schemas {
119                         get { return descriptionImporter.Schemas; }
120                 }
121
122                 public Service Service {
123                         get { return service; } 
124                 }
125
126                 public ServiceDescriptionCollection ServiceDescriptions {
127                         get { return descriptionImporter.ServiceDescriptions; }
128                 }
129
130                 public ServiceDescriptionImportStyle Style {
131                         get { return descriptionImporter.Style; }
132                 }
133
134                 public ServiceDescriptionImportWarnings Warnings {
135                         get { return warnings; }
136                         set { warnings = value; }
137                 }
138                 
139                 internal ImportInfo ImportInfo
140                 {
141                         get { return iinfo; }
142                 }
143
144                 #endregion // Properties
145
146                 #region Methods
147                 
148                 internal bool Import (ServiceDescriptionImporter descriptionImporter, CodeNamespace codeNamespace, CodeCompileUnit codeCompileUnit, ArrayList importInfo)
149                 {
150                         this.descriptionImporter = descriptionImporter;
151                         this.classNames = new CodeIdentifiers();;
152                         this.codeNamespace = codeNamespace;
153                         this.codeCompileUnit = codeCompileUnit;
154                         
155                         warnings = (ServiceDescriptionImportWarnings) 0;
156                         
157                         bool found = false;
158
159                         BeginNamespace ();
160                         
161                         foreach (ImportInfo info in importInfo)
162                         {
163                                 foreach (Service service in info.ServiceDescription.Services)
164                                 {
165                                         this.service = service;
166                                         foreach (Port port in service.Ports)
167                                         {
168                                                 this.iinfo = info;
169                                                 this.port = port;
170                                                 binding = ServiceDescriptions.GetBinding (port.Binding);
171                                                 if (!IsBindingSupported ()) continue;
172                                                 
173                                                 found = true;
174                                                 ImportPortBinding ();
175                                         }
176                                 }
177                         }
178
179                         EndNamespace ();
180                         
181                         return true;
182                 }
183
184                 void ImportPortBinding ()
185                 {
186                         if (service.Ports.Count > 1) className = port.Name;
187                         else className = service.Name;
188                         
189                         className = classNames.AddUnique (CodeIdentifier.MakeValid (className), port);
190                         
191                         try
192                         {
193                                 portType = ServiceDescriptions.GetPortType (binding.Type);
194                                 if (portType == null) throw new Exception ("Port type not found: " + binding.Type);
195
196                                 CodeTypeDeclaration codeClass = BeginClass ();
197                                 codeTypeDeclaration = codeClass;
198                                 AddCodeType (codeClass, port.Documentation);
199                                 codeClass.Attributes = MemberAttributes.Public;
200                                 
201                                 if (service.Documentation != null && service.Documentation != "")
202                                         AddComments (codeClass, service.Documentation);
203
204                                 CodeAttributeDeclaration att = new CodeAttributeDeclaration ("System.Diagnostics.DebuggerStepThroughAttribute");
205                                 AddCustomAttribute (codeClass, att, true);
206
207                                 att = new CodeAttributeDeclaration ("System.ComponentModel.DesignerCategoryAttribute");
208                                 att.Arguments.Add (GetArg ("code"));
209                                 AddCustomAttribute (codeClass, att, true);
210
211                                 if (binding.Operations.Count == 0) {
212                                         warnings |= ServiceDescriptionImportWarnings.NoMethodsGenerated;
213                                         return;
214                                 }
215                                 
216                                 foreach (OperationBinding oper in binding.Operations) 
217                                 {
218                                         operationBinding = oper;
219                                         operation = FindPortOperation ();
220                                         if (operation == null) throw new Exception ("Operation " + operationBinding.Name + " not found in portType " + PortType.Name);
221
222                                         foreach (OperationMessage omsg in operation.Messages)
223                                         {
224                                                 Message msg = ServiceDescriptions.GetMessage (omsg.Message);
225                                                 if (msg == null) throw new Exception ("Message not found: " + omsg.Message);
226                                                 
227                                                 if (omsg is OperationInput)
228                                                         inputMessage = msg;
229                                                 else
230                                                         outputMessage = msg;
231                                         }
232                                         
233                                         CodeMemberMethod method = GenerateMethod ();
234                                         
235                                         if (method != null)
236                                         {
237                                                 methodName = method.Name;
238                                                 if (operation.Documentation != null && operation.Documentation != "")
239                                                         AddComments (method, operation.Documentation);
240                                         }
241                                 }
242                                 
243                                 EndClass ();
244                         }
245                         catch (Exception ex)
246                         {
247                                 warnings |= ServiceDescriptionImportWarnings.NoCodeGenerated;
248                                 UnsupportedBindingWarning (ex.Message);
249                         }
250                 }
251
252                 Operation FindPortOperation ()
253                 {
254                         string inMessage = (operationBinding.Input.Name != "") ? operationBinding.Input.Name : operationBinding.Name;
255                         string outMessage = (operationBinding.Output.Name != "") ? operationBinding.Output.Name : operationBinding.Name;
256                         string operName = operationBinding.Name;
257                         
258                         foreach (Operation oper in PortType.Operations)
259                         {
260                                 if (oper.Name == operName)
261                                 {
262                                         int hits = 0;
263                                         foreach (OperationMessage omsg in oper.Messages)
264                                         {
265                                                 if (omsg is OperationInput && GetOperMessageName (omsg, operName) == inMessage) hits++;
266                                                 if (omsg is OperationOutput && GetOperMessageName (omsg, operName) == outMessage) hits++;
267                                         }
268                                         if (hits == 2) return oper;
269                                 }
270                         }
271                         return null;
272                 }
273                 
274                 string GetOperMessageName (OperationMessage msg, string operName)
275                 {
276                         if (msg.Name == null) return operName;
277                         else return msg.Name;
278                 }
279                 
280                 internal string GetServiceUrl (string location)
281                 {
282                         if (ImportInfo.AppSettingUrlKey == null || ImportInfo.AppSettingUrlKey == string.Empty)
283                                 return location;
284                         else
285                         {
286                                 string url;
287                                 if (Style == ServiceDescriptionImportStyle.Server) throw new InvalidOperationException ("Cannot set appSettingUrlKey if Style is Server");
288                                 url = ConfigurationSettings.AppSettings [ImportInfo.AppSettingUrlKey];
289                                 if (ImportInfo.AppSettingBaseUrl != null && ImportInfo.AppSettingBaseUrl != string.Empty)
290                                         url += "/" + ImportInfo.AppSettingBaseUrl + "/" + location;
291                                 return url;
292                         }
293                 }
294
295                 
296                 [MonoTODO]
297                 public void AddExtensionWarningComments (CodeCommentStatementCollection comments, ServiceDescriptionFormatExtensionCollection extensions) 
298                 {
299                         throw new NotImplementedException ();
300                 }
301
302                 protected abstract CodeTypeDeclaration BeginClass ();
303
304                 protected virtual void BeginNamespace ()
305                 {
306                 }
307
308                 protected virtual void EndClass ()
309                 {
310                 }
311
312                 protected virtual void EndNamespace ()
313                 {
314                 }
315
316                 protected abstract CodeMemberMethod GenerateMethod ();
317                 protected abstract bool IsBindingSupported ();
318                 protected abstract bool IsOperationFlowSupported (OperationFlow flow);
319                 
320                 [MonoTODO]
321                 public Exception OperationBindingSyntaxException (string text)
322                 {
323                         throw new NotImplementedException ();
324                 }
325
326                 [MonoTODO]
327                 public Exception OperationSyntaxException (string text)
328                 {
329                         throw new NotImplementedException ();
330                 }
331
332                 public void UnsupportedBindingWarning (string text)
333                 {
334                         AddGlobalComments ("WARNING: Could not generate proxy for binding " + binding.Name + ". " + text);
335                 }
336
337                 public void UnsupportedOperationBindingWarning (string text)
338                 {
339                         AddGlobalComments ("WARNING: Could not generate operation " + OperationBinding.Name + ". " + text);
340                 }
341
342                 public void UnsupportedOperationWarning (string text)
343                 {
344                         AddGlobalComments ("WARNING: Could not generate operation " + OperationBinding.Name + ". " + text);
345                 }
346
347                 void AddGlobalComments (string comments)
348                 {
349                         codeNamespace.Comments.Add (new CodeCommentStatement (comments, false));
350                 }
351
352                 void AddComments (CodeTypeMember member, string comments)
353                 {
354                         if (comments == null || comments == "") member.Comments.Add (new CodeCommentStatement ("<remarks/>", true));
355                         else member.Comments.Add (new CodeCommentStatement ("<remarks>\n" + comments + "\n</remarks>", true));
356                 }
357
358                 void AddCodeType (CodeTypeDeclaration type, string comments)
359                 {
360                         AddComments (type, comments);
361                         codeNamespace.Types.Add (type);
362                 }
363
364                 internal void AddCustomAttribute (CodeTypeMember ctm, CodeAttributeDeclaration att, bool addIfNoParams)
365                 {
366                         if (att.Arguments.Count == 0 && !addIfNoParams) return;
367                         
368                         if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
369                         ctm.CustomAttributes.Add (att);
370                 }
371
372                 internal void AddCustomAttribute (CodeTypeMember ctm, string name, params CodeAttributeArgument[] args)
373                 {
374                         if (ctm.CustomAttributes == null) ctm.CustomAttributes = new CodeAttributeDeclarationCollection ();
375                         ctm.CustomAttributes.Add (new CodeAttributeDeclaration (name, args));
376                 }
377
378                 internal CodeAttributeArgument GetArg (string name, object value)
379                 {
380                         return new CodeAttributeArgument (name, new CodePrimitiveExpression(value));
381                 }
382
383                 internal CodeAttributeArgument GetEnumArg (string name, string enumType, string enumValue)
384                 {
385                         return new CodeAttributeArgument (name, new CodeFieldReferenceExpression (new CodeTypeReferenceExpression(enumType), enumValue));
386                 }
387
388                 internal CodeAttributeArgument GetArg (object value)
389                 {
390                         return new CodeAttributeArgument (new CodePrimitiveExpression(value));
391                 }
392
393                 internal CodeAttributeArgument GetTypeArg (string name, string typeName)
394                 {
395                         return new CodeAttributeArgument (name, new CodeTypeOfExpression(typeName));
396                 }
397                 
398                 #endregion
399         }
400 }