This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / tools / wsdl / MonoWSDL.cs
1 ///\r
2 /// MonoWSDL.cs -- a WSDL to proxy code generator.\r
3 ///\r
4 /// Author: Erik LeBel (eriklebel@yahoo.ca)\r
5 ///             Lluis Sanchez (lluis@ximian.com)\r
6 ///\r
7 /// Copyright (C) 2003, Erik LeBel,\r
8 ///\r
9 \r
10 using System;\r
11 using System.Xml;\r
12 using System.Xml.Schema;\r
13 using System.Collections;\r
14 using System.CodeDom;\r
15 using System.CodeDom.Compiler;\r
16 using System.IO;\r
17 using System.Net;\r
18 using System.Web.Services.Description;\r
19 using System.Web.Services.Discovery;\r
20 \r
21 using Microsoft.CSharp;\r
22 \r
23 namespace Mono.WebServices\r
24 {\r
25         ///\r
26         /// <summary>\r
27         ///     Source code generator.\r
28         /// </summary>\r
29         ///\r
30         class SourceGenerator\r
31         {\r
32                 string applicationSiganture     = null;\r
33                 string appSettingURLKey         = null;\r
34                 string appSettingBaseURL        = null;\r
35                 string language                 = "CS";\r
36                 string ns                       = null;\r
37                 string outFilename              = null;\r
38                 string protocol                 = "Soap";\r
39                 bool   server                   = false;\r
40                 \r
41                 ///\r
42                 /// <summary/>\r
43                 ///\r
44                 public string Language \r
45                 {\r
46                         // FIXME validate\r
47                         set { language = value; }\r
48                 }\r
49                 \r
50                 ///\r
51                 /// <summary/>\r
52                 ///\r
53                 public string Namespace \r
54                 {\r
55                         set { ns = value; }\r
56                 }\r
57                 \r
58                 ///\r
59                 /// <summary>\r
60                 ///     The file to contain the generated code.\r
61                 /// </summary>\r
62                 ///\r
63                 public string Filename\r
64                 {\r
65                         set { outFilename = value; }\r
66                 }\r
67                 \r
68                 ///\r
69                 /// <summary/>\r
70                 ///\r
71                 public string Protocol\r
72                 {\r
73                         // FIXME validate\r
74                         set { protocol = value; }\r
75                         get { return protocol; }\r
76                 }\r
77                 \r
78                 ///\r
79                 /// <summary/>\r
80                 ///\r
81                 public string ApplicationSignature\r
82                 {\r
83                         set { applicationSiganture = value; }\r
84                 }\r
85                 \r
86                 ///\r
87                 /// <summary/>\r
88                 ///\r
89                 public string AppSettingURLKey\r
90                 {\r
91                         set { appSettingURLKey = value; }\r
92                 }\r
93                 \r
94                 ///\r
95                 /// <summary/>\r
96                 ///\r
97                 public string AppSettingBaseURL \r
98                 {\r
99                         set { appSettingBaseURL  = value; }\r
100                 }\r
101                 \r
102                 ///\r
103                 /// <summary/>\r
104                 ///\r
105                 public bool Server\r
106                 {\r
107                         set { server = value; }\r
108                 }\r
109                 \r
110                 ///\r
111                 /// <summary>\r
112                 ///     Generate code for the specified ServiceDescription.\r
113                 /// </summary>\r
114                 ///\r
115                 public bool GenerateCode (ArrayList descriptions, ArrayList schemas)\r
116                 {\r
117                         // FIXME iterate over each serviceDescription.Services?\r
118                         CodeNamespace codeNamespace = GetCodeNamespace();\r
119                         CodeCompileUnit codeUnit = new CodeCompileUnit();\r
120                         bool hasWarnings = false;\r
121                         \r
122                         codeUnit.Namespaces.Add(codeNamespace);\r
123 \r
124                         ServiceDescriptionImporter importer = new ServiceDescriptionImporter();\r
125                         importer.ProtocolName = protocol;\r
126                         if (server)\r
127                                 importer.Style = ServiceDescriptionImportStyle.Server;\r
128                         \r
129                         foreach (ServiceDescription sd in descriptions)\r
130                                 importer.AddServiceDescription(sd, appSettingURLKey, appSettingBaseURL);\r
131                                 \r
132                         foreach (XmlSchema sc in schemas)\r
133                                 importer.Schemas.Add (sc);\r
134                         \r
135                         ServiceDescriptionImportWarnings warnings = importer.Import(codeNamespace, codeUnit);\r
136                         if (warnings != 0)\r
137                         {\r
138                                 if ((warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)\r
139                                         Console.WriteLine ("WARNING: No proxy class was generated"); \r
140                                 if ((warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)\r
141                                         Console.WriteLine ("WARNING: The proxy class generated includes no methods");\r
142                                 if ((warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)\r
143                                         Console.WriteLine ("WARNING: At least one optional extension has been ignored");\r
144                                 if ((warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)\r
145                                         Console.WriteLine ("WARNING: At least one necessary extension has been ignored");\r
146                                 if ((warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)\r
147                                         Console.WriteLine ("WARNING: At least one binding is of an unsupported type and has been ignored");\r
148                                 if ((warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)\r
149                                         Console.WriteLine ("WARNING: At least one operation is of an unsupported type and has been ignored");\r
150                                 hasWarnings = true;\r
151                         }\r
152                         
153                         ServiceDescription rootDesc = null;
154                         foreach (ServiceDescription desc in descriptions) {
155                                 if (desc.Services.Count > 0) {
156                                         rootDesc = desc;
157                                         break;
158                                 }
159                         }
160                                 \r
161                         if (rootDesc != null)\r
162                         {\r
163                                 string serviceName = rootDesc.Services[0].Name;\r
164                                 WriteCodeUnit(codeUnit, serviceName);\r
165                         }\r
166                         \r
167                         return hasWarnings;\r
168                 }\r
169                 \r
170                 ///\r
171                 /// <summary>\r
172                 ///     Create the CodeNamespace with the generator's signature commented in.\r
173                 /// </summary>\r
174                 ///\r
175                 CodeNamespace GetCodeNamespace()\r
176                 {\r
177                         CodeNamespace codeNamespace = new CodeNamespace(ns);\r
178                         \r
179                         if (applicationSiganture != null)\r
180                         {\r
181                                 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSiganture + "\n"));\r
182                         }\r
183                         \r
184                         return codeNamespace;\r
185                 }\r
186                 \r
187                 ///\r
188                 /// <summary/>\r
189                 ///\r
190                 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)\r
191                 {\r
192                         CodeDomProvider provider = GetProvider();\r
193                         ICodeGenerator generator = provider.CreateGenerator();\r
194                         CodeGeneratorOptions options = new CodeGeneratorOptions();\r
195                         \r
196                         string filename;\r
197                         if (outFilename != null)\r
198                                 filename = outFilename;\r
199                         else\r
200                                 filename = serviceName  + "." + provider.FileExtension;\r
201                         \r
202                         Console.WriteLine ("Writing file '{0}'", filename);\r
203                         StreamWriter writer = new StreamWriter(filename);\r
204                         generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);\r
205                         writer.Close();\r
206                 }\r
207                 \r
208                 ///\r
209                 /// <summary>\r
210                 ///     Fetch the Code Provider for the language specified by the 'language' members.\r
211                 /// </summary>\r
212                 ///\r
213                 private CodeDomProvider GetProvider()\r
214                 {\r
215                         // FIXME these should be loaded dynamically using reflection\r
216                         CodeDomProvider provider;\r
217                         \r
218                         switch (language.ToUpper())\r
219                         {\r
220                             case "CS":\r
221                                     provider = new CSharpCodeProvider();\r
222                                     break;\r
223                             \r
224                                 case "VB":\r
225                                         provider = new Microsoft.VisualBasic.VBCodeProvider();\r
226                                         break;\r
227                                         \r
228                             default:\r
229                                     throw new Exception("Unknow language");\r
230                         }\r
231 \r
232                         return provider;\r
233                 }\r
234         }\r
235         \r
236         ///\r
237         /// <summary>\r
238         ///     monoWSDL's main application driver. Reads the command-line arguments and dispatch the\r
239         ///     appropriate handlers.\r
240         /// </summary>\r
241         ///\r
242         public class Driver\r
243         {\r
244                 const string ProductId = "Mono Web Services Description Language Utility";\r
245                 const string UsageMessage = \r
246                         "wsdl [options] {path | URL} \n\n"\r
247                         + "   -d, -domain:domain           Domain of username for server authentication.\n"\r
248                         + "   -l, -language:language       Language of generated code. Allowed CS (default)\n"\r
249                         + "                                and VB.\n"\r
250                         + "   -n, -namespace:ns            The namespace of the generated code, default\n"\r
251                         + "                                namespace if none.\n"\r
252                         + "   -nologo                      Surpress the startup logo.\n"\r
253                         + "   -o, -out:filename            The target file for generated code.\n"\r
254                         + "   -p, -password:pwd            Password used to contact the server.\n"\r
255                         + "   -protocol:protocol           Protocol to implement. Allowed: Soap (default),\n"\r
256                         + "                                HttpGet or HttpPost.\n"\r
257                         + "   -server                      Generate server instead of client proxy code.\n"\r
258                         + "   -u, -username:username       Username used to contact the server.\n"\r
259                         + "   -proxy:url                   Address of the proxy.\n"\r
260                         + "   -pu, -proxyusername:username Username used to contact the proxy.\n"\r
261                         + "   -pp, -proxypassword:pwd      Password used to contact the proxy.\n"\r
262                         + "   -pd, -proxydomain:domain     Domain of username for proxy authentication.\n"\r
263                         + "   -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"\r
264                         + "                                url for the generated WS proxy.\n"\r
265                         + "   -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"\r
266                         + "                                service url.\n"\r
267                         + "   -sample:[binding/]operation  Display a sample SOAP request and response.\n"\r
268                         + "   -?                           Display this message\n"\r
269                         + "\n"\r
270                         + "Options can be of the forms  -option, --option or /option\n";\r
271                 \r
272                 SourceGenerator generator = null;\r
273                 \r
274                 ArrayList descriptions = new ArrayList ();\r
275                 ArrayList schemas = new ArrayList ();\r
276                 \r
277                 bool noLogo = false;\r
278                 bool help = false;\r
279                 bool hasURL = false;\r
280                 string sampleSoap = null;\r
281                 \r
282                 string proxyAddress = null;\r
283                 string proxyDomain = null;\r
284                 string proxyPassword = null;\r
285                 string proxyUsername = null;\r
286                 string username;\r
287                 string password;\r
288                 string domain;\r
289                 \r
290                 string url;\r
291 \r
292                 ///\r
293                 /// <summary>\r
294                 ///     Initialize the document retrieval component and the source code generator.\r
295                 /// </summary>\r
296                 ///\r
297                 Driver()\r
298                 {\r
299                         generator = new SourceGenerator();\r
300                         generator.ApplicationSignature = ProductId;\r
301                 }\r
302                 \r
303                 ///\r
304                 /// <summary>\r
305                 ///     Interperet the command-line arguments and configure the relavent components.\r
306                 /// </summary>\r
307                 ///             \r
308                 void ImportArgument(string argument)\r
309                 {\r
310                         string optionValuePair;\r
311                         \r
312                         if (argument.StartsWith("--"))\r
313                         {\r
314                                 optionValuePair = argument.Substring(2);\r
315                         }\r
316                         else if (argument.StartsWith("/") || argument.StartsWith("-"))\r
317                         {\r
318                                 optionValuePair = argument.Substring(1);\r
319                         }\r
320                         else\r
321                         {\r
322                                 hasURL = true;\r
323                                 url = argument;\r
324                                 return;\r
325                         }\r
326                         \r
327                         string option;\r
328                         string value;\r
329                         \r
330                         int indexOfEquals = optionValuePair.IndexOf(':');\r
331                         if (indexOfEquals > 0)\r
332                         {\r
333                                 option = optionValuePair.Substring(0, indexOfEquals);\r
334                                 value = optionValuePair.Substring(indexOfEquals + 1);\r
335                         }\r
336                         else\r
337                         {\r
338                                 option = optionValuePair;\r
339                                 value = null;\r
340                         }\r
341                         \r
342                         switch (option)\r
343                         {\r
344                                 case "appsettingurlkey":\r
345                                 case "urlkey":\r
346                                     generator.AppSettingURLKey = value;\r
347                                     break;\r
348 \r
349                                 case "appsettingbaseurl":\r
350                                 case "baseurl":\r
351                                     generator.AppSettingBaseURL = value;\r
352                                     break;\r
353 \r
354                                 case "d":\r
355                                 case "domain":\r
356                                     domain = value;\r
357                                     break;\r
358 \r
359                                 case "l":\r
360                                 case "language":\r
361                                     generator.Language = value;\r
362                                     break;\r
363 \r
364                                 case "n":\r
365                                 case "namespace":\r
366                                     generator.Namespace = value;\r
367                                     break;\r
368 \r
369                                 case "nologo":\r
370                                     noLogo = true;\r
371                                     break;\r
372 \r
373                                 case "o":\r
374                                 case "out":\r
375                                     generator.Filename = value;\r
376                                     break;\r
377 \r
378                                 case "p":\r
379                                 case "password":\r
380                                     password = value;\r
381                                     break;\r
382 \r
383                                 case "protocol":\r
384                                     generator.Protocol = value;\r
385                                     break;\r
386 \r
387                                 case "proxy":\r
388                                     proxyAddress = value;\r
389                                     break;\r
390 \r
391                                 case "proxydomain":\r
392                                 case "pd":\r
393                                     proxyDomain = value;\r
394                                     break;\r
395 \r
396                                 case "proxypassword":\r
397                                 case "pp":\r
398                                     proxyPassword = value;\r
399                                     break;\r
400 \r
401                                 case "proxyusername":\r
402                                 case "pu":\r
403                                     proxyUsername = value;\r
404                                     break;\r
405 \r
406                                 case "server":\r
407                                     generator.Server = true;\r
408                                     break;\r
409 \r
410                                 case "u":\r
411                                 case "username":\r
412                                     username = value;\r
413                                     break;\r
414                                         \r
415                                 case "sample":\r
416                                         sampleSoap = value;\r
417                                         break;\r
418 \r
419                                 case "?":\r
420                                     help = true;\r
421                                     break;\r
422 \r
423                                 default:\r
424                                     throw new Exception("Unknown option " + option);\r
425                         }\r
426                 }\r
427                 \r
428                 DiscoveryClientProtocol CreateClient ()\r
429                 {\r
430                         DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();\r
431                         \r
432                         if (username != null || password != null || domain != null)\r
433                         {\r
434                                 NetworkCredential credentials = new NetworkCredential();\r
435                                 \r
436                                 if (username != null)\r
437                                         credentials.UserName = username;\r
438                                 \r
439                                 if (password != null)\r
440                                         credentials.Password = password;\r
441                                 \r
442                                 if (domain != null)\r
443                                         credentials.Domain = domain;\r
444                                 \r
445                                 dcc.Credentials = credentials;\r
446                         }\r
447                         \r
448                         if (proxyAddress != null)\r
449                         {\r
450                                 WebProxy proxy = new WebProxy (proxyAddress);\r
451                                 if (proxyUsername != null || proxyPassword != null || proxyDomain != null)\r
452                                 {\r
453                                         NetworkCredential credentials = new NetworkCredential();\r
454                                         \r
455                                         if (proxyUsername != null)\r
456                                                 credentials.UserName = proxyUsername;\r
457                                         \r
458                                         if (proxyPassword != null)\r
459                                                 credentials.Password = proxyPassword;\r
460                                         \r
461                                         if (proxyDomain != null)\r
462                                                 credentials.Domain = proxyDomain;\r
463                                         \r
464                                         proxy.Credentials = credentials;\r
465                                 }\r
466                         }                       \r
467                         \r
468                         return dcc;\r
469                 }\r
470 \r
471                 ///\r
472                 /// <summary>\r
473                 ///     Driver's main control flow:\r
474                 ///      - parse arguments\r
475                 ///      - report required messages\r
476                 ///      - terminate if no input\r
477                 ///      - report errors\r
478                 /// </summary>\r
479                 ///\r
480                 int Run(string[] args)\r
481                 {\r
482                         try\r
483                         {\r
484                                 // parse command line arguments\r
485                                 foreach (string argument in args)\r
486                                 {\r
487                                         ImportArgument(argument);\r
488                                 }\r
489                                 \r
490                                 if (noLogo == false)\r
491                                         Console.WriteLine(ProductId);\r
492                                 \r
493                                 if (help || !hasURL)\r
494                                 {\r
495                                         Console.WriteLine(UsageMessage);\r
496                                         return 0;\r
497                                 }\r
498                                 \r
499                                 DiscoveryClientProtocol dcc = CreateClient ();\r
500                                                                 \r
501                                 dcc.DiscoverAny (url);\r
502                                 dcc.ResolveAll ();\r
503                                 \r
504                                 foreach (object doc in dcc.Documents.Values)\r
505                                 {\r
506                                         if (doc is ServiceDescription)\r
507                                                 descriptions.Add ((ServiceDescription)doc);\r
508                                         else if (doc is XmlSchema)\r
509                                                 schemas.Add ((XmlSchema)doc);\r
510                                 }\r
511                                 \r
512                                 if (descriptions.Count == 0)\r
513                                         throw new Exception ("No WSDL document was found at the url " + url);\r
514                                 \r
515                                 if (sampleSoap != null)\r
516                                 {\r
517                                         ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, generator.Protocol);\r
518                                         return 0;\r
519                                 }\r
520                                 \r
521                                 // generate the code\r
522                                 if (generator.GenerateCode (descriptions, schemas))\r
523                                         return 1;\r
524                                 else\r
525                                         return 0;\r
526                         }\r
527                         catch (Exception exception)\r
528                         {\r
529                                 Console.WriteLine("Error: {0}", exception.Message);\r
530                                 // FIXME: surpress this except for when debug is enabled\r
531                                 //Console.WriteLine("Stack:\n {0}", exception.StackTrace);\r
532                                 return 2;\r
533                         }\r
534                 }\r
535                                 \r
536                 ///\r
537                 /// <summary>\r
538                 ///     Application entry point.\r
539                 /// </summary>\r
540                 ///\r
541                 public static int Main(string[] args)\r
542                 {\r
543                         Driver d = new Driver();\r
544                         return d.Run(args);\r
545                 }\r
546         }\r
547 }