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