update readme (#21797)
[mono-project.git] / mcs / tools / wsdl / MonoWSDL2.cs
blob2b00b58c29179b6a2606aa82bf6a829a6de4bf1d
1 ///
2 /// MonoWSDL.cs -- a WSDL to proxy code generator.
3 ///
4 /// Author: Erik LeBel (eriklebel@yahoo.ca)
5 /// Lluis Sanchez (lluis@novell.com)
6 ///
7 /// Copyright (C) 2003, Erik LeBel,
8 ///
11 using System;
12 using System.Xml;
13 using System.Xml.Serialization;
14 using System.Xml.Schema;
15 using System.Collections;
16 using System.Collections.Specialized;
17 using System.CodeDom;
18 using System.CodeDom.Compiler;
19 using System.IO;
20 using System.Net;
21 using System.Web.Services.Description;
22 using System.Web.Services.Discovery;
23 using System.Web.Services;
25 using Microsoft.CSharp;
27 namespace Mono.WebServices
29 public class Driver
31 string ProductId = "Web Services Description Language Utility\nMono Framework v" + Environment.Version;
32 const string UsageMessage =
33 "wsdl [options] {path | URL} {path | URL} ...\n\n"
34 + " -d, -domain:domain Domain of username for server authentication.\n"
35 + " -l, -language:language Language of generated code. Allowed CS (default)\n"
36 + " and VB. You can also specify the fully qualified\n"
37 + " name of a class that implements the\n"
38 + " System.CodeDom.Compiler.CodeDomProvider Class.\n"
39 + " -n, -namespace:ns The namespace of the generated code, default\n"
40 + " namespace if none.\n"
41 + " -nologo Surpress the startup logo.\n"
42 + " -o, -out:filename The target file for generated code.\n"
43 + " -p, -password:pwd Password used to contact the server.\n"
44 + " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n"
45 + " HttpGet or HttpPost.\n"
46 + " -fields Generate fields instead of properties in data\n"
47 + " classes.\n"
48 + " -server Generate server instead of client proxy code.\n"
49 + " -u, -username:username Username used to contact the server.\n"
50 + " -proxy:url Address of the proxy.\n"
51 + " -pu, -proxyusername:username Username used to contact the proxy.\n"
52 + " -pp, -proxypassword:pwd Password used to contact the proxy.\n"
53 + " -pd, -proxydomain:domain Domain of username for proxy authentication.\n"
54 + " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"
55 + " url for the generated WS proxy.\n"
56 + " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"
57 + " service url.\n"
58 + " -sample:[binding/]operation Display a sample SOAP request and response.\n"
59 + " -? Display this message\n"
60 + "\n"
61 + "Options can be of the forms -option, --option or /option\n";
63 ArrayList descriptions = new ArrayList ();
64 ArrayList schemas = new ArrayList ();
66 bool noLogo;
67 bool help;
68 string sampleSoap;
70 string proxyAddress;
71 string proxyDomain;
72 string proxyPassword;
73 string proxyUsername;
74 string username;
75 string password;
76 string domain;
78 string applicationSignature;
79 string appSettingURLKey;
80 string appSettingBaseURL;
81 string language = "CS";
82 string ns;
83 string outFilename;
84 string protocol = "Soap";
85 ServiceDescriptionImportStyle style;
86 CodeGenerationOptions options = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
87 bool verbose;
89 StringCollection urls = new StringCollection ();
91 ///
92 /// <summary>
93 /// Application entry point.
94 /// </summary>
95 ///
96 public static int Main(string[] args)
98 Driver d = new Driver();
99 return d.Run(args);
102 Driver()
104 applicationSignature = ProductId;
107 int Run (string[] args)
111 // parse command line arguments
112 foreach (string argument in args)
113 ImportArgument(argument);
115 if (noLogo == false)
116 Console.WriteLine(ProductId);
118 if (help || urls.Count == 0)
120 Console.WriteLine(UsageMessage);
121 return 0;
124 CodeCompileUnit codeUnit = new CodeCompileUnit();
125 CodeNamespace proxyCode = GetCodeNamespace();
126 codeUnit.Namespaces.Add (proxyCode);
128 WebReferenceCollection references = new WebReferenceCollection ();
130 DiscoveryClientProtocol dcc = CreateClient ();
132 foreach (string murl in urls)
135 string url = murl;
136 if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://"))
137 url = new Uri (Path.GetFullPath (url)).ToString ();
139 dcc.DiscoverAny (url);
140 dcc.ResolveAll ();
144 WebReference reference = new WebReference (dcc.Documents, proxyCode, protocol, appSettingURLKey, appSettingBaseURL);
145 references.Add (reference);
147 if (sampleSoap != null)
148 ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, protocol);
150 if (sampleSoap != null)
151 return 0;
153 // generate the code
154 GenerateCode (references, codeUnit);
155 return 0;
157 catch (Exception exception)
159 Console.WriteLine("Error: {0}", exception.Message);
161 // Supress this except for when debug is enabled
162 Console.WriteLine("Stack:\n {0}", exception.StackTrace);
163 return 2;
168 /// <summary>
169 /// Generate code for the specified ServiceDescription.
170 /// </summary>
172 public bool GenerateCode (WebReferenceCollection references, CodeCompileUnit codeUnit)
174 bool hasWarnings = false;
176 CodeDomProvider provider = GetProvider();
178 StringCollection validationWarnings;
179 WebReferenceOptions opts = new WebReferenceOptions ();
180 opts.CodeGenerationOptions = options;
181 opts.Style = style;
182 opts.Verbose = verbose;
183 validationWarnings = ServiceDescriptionImporter.GenerateWebReferences (references, provider, codeUnit, opts);
185 for (int n=0; n<references.Count; n++)
187 WebReference wr = references [n];
189 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
190 if (String.Compare (protocol, "SOAP", StringComparison.OrdinalIgnoreCase) == 0 && !WebServicesInteroperability.CheckConformance (WsiProfiles.BasicProfile1_1, wr, violations)) {
191 wr.Warnings |= ServiceDescriptionImportWarnings.WsiConformance;
194 if (wr.Warnings != 0)
196 if (!hasWarnings) {
197 WriteText ("", 0, 0);
198 WriteText ("There were some warnings while generating the code:", 0, 0);
201 WriteText ("", 0, 0);
202 WriteText (urls[n], 2, 2);
204 if ((wr.Warnings & ServiceDescriptionImportWarnings.WsiConformance) > 0) {
205 WriteText ("- This web reference does not conform to WS-I Basic Profile v1.1", 4, 6);
206 foreach (BasicProfileViolation vio in violations) {
207 WriteText (vio.NormativeStatement + ": " + vio.Details, 8, 8);
208 foreach (string ele in vio.Elements)
209 WriteText ("* " + ele, 10, 12);
213 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)
214 WriteText ("- WARNING: No proxy class was generated", 4, 6);
215 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)
216 WriteText ("- WARNING: The proxy class generated includes no methods", 4, 6);
217 if ((wr.Warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)
218 WriteText ("- WARNING: At least one optional extension has been ignored", 4, 6);
219 if ((wr.Warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)
220 WriteText ("- WARNING: At least one necessary extension has been ignored", 4, 6);
221 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)
222 WriteText ("- WARNING: At least one binding is of an unsupported type and has been ignored", 4, 6);
223 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)
224 WriteText ("- WARNING: At least one operation is of an unsupported type and has been ignored", 4, 6);
226 hasWarnings = true;
230 if (hasWarnings) WriteText ("",0,0);
232 string filename = outFilename;
233 bool hasBindings = false;
235 foreach (object doc in references[0].Documents.Values)
237 ServiceDescription desc = doc as ServiceDescription;
238 if (desc == null) continue;
240 if (desc.Services.Count > 0 && filename == null)
241 filename = desc.Services[0].Name + "." + provider.FileExtension;
243 if (desc.Bindings.Count > 0 || desc.Services.Count > 0)
244 hasBindings = true;
247 if (filename == null)
248 filename = "output." + provider.FileExtension;
250 if (hasBindings) {
251 WriteText ("Writing file '" + filename + "'", 0, 0);
252 StreamWriter writer = new StreamWriter(filename);
254 CodeGeneratorOptions compilerOptions = new CodeGeneratorOptions();
255 provider.GenerateCodeFromCompileUnit (codeUnit, writer, compilerOptions);
256 writer.Close();
259 return hasWarnings;
263 /// <summary>
264 /// Create the CodeNamespace with the generator's signature commented in.
265 /// </summary>
267 CodeNamespace GetCodeNamespace()
269 CodeNamespace codeNamespace = new CodeNamespace(ns);
271 if (applicationSignature != null)
273 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSignature + "\n"));
276 return codeNamespace;
280 /// <summary/>
282 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)
284 CodeDomProvider provider = GetProvider();
285 ICodeGenerator generator = provider.CreateGenerator();
286 CodeGeneratorOptions options = new CodeGeneratorOptions();
288 string filename;
289 if (outFilename != null)
290 filename = outFilename;
291 else
292 filename = serviceName + "." + provider.FileExtension;
294 Console.WriteLine ("Writing file '{0}'", filename);
295 StreamWriter writer = new StreamWriter(filename);
296 generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);
297 writer.Close();
301 /// <summary>
302 /// Fetch the Code Provider for the language specified by the 'language' members.
303 /// </summary>
305 private CodeDomProvider GetProvider()
307 CodeDomProvider provider;
308 Type type;
310 switch (language.ToUpper ()) {
311 case "CS":
312 provider = new CSharpCodeProvider ();
313 break;
314 case "VB":
315 provider = new Microsoft.VisualBasic.VBCodeProvider ();
316 break;
317 case "BOO":
318 type = Type.GetType("Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67");
319 if (type != null){
320 return (CodeDomProvider) Activator.CreateInstance (type);
322 throw new Exception ("Boo.Lang.CodeDom.BooCodeProvider not available");
324 default:
325 type = Type.GetType(language);
326 if (type != null) {
327 return (CodeDomProvider) Activator.CreateInstance (type);
329 throw new Exception ("Unknown language");
331 return provider;
337 /// <summary>
338 /// Interperet the command-line arguments and configure the relavent components.
339 /// </summary>
340 ///
341 void ImportArgument(string argument)
343 string optionValuePair;
345 if (argument.StartsWith("--"))
347 optionValuePair = argument.Substring(2);
349 else if (argument.StartsWith("/") || argument.StartsWith("-"))
351 optionValuePair = argument.Substring(1);
353 else
355 urls.Add (argument);
356 return;
359 string option;
360 string value;
362 int indexOfEquals = optionValuePair.IndexOf(':');
363 if (indexOfEquals > 0)
365 option = optionValuePair.Substring(0, indexOfEquals);
366 value = optionValuePair.Substring(indexOfEquals + 1);
368 else
370 option = optionValuePair;
371 value = null;
374 switch (option)
376 case "appsettingurlkey":
377 case "urlkey":
378 appSettingURLKey = value;
379 break;
381 case "appsettingbaseurl":
382 case "baseurl":
383 appSettingBaseURL = value;
384 break;
386 case "d":
387 case "domain":
388 domain = value;
389 break;
391 case "l":
392 case "language":
393 language = value;
394 break;
396 case "n":
397 case "namespace":
398 ns = value;
399 break;
401 case "nologo":
402 noLogo = true;
403 break;
405 case "o":
406 case "out":
407 outFilename = value;
408 break;
410 case "p":
411 case "password":
412 password = value;
413 break;
415 case "protocol":
416 protocol = value;
417 break;
419 case "proxy":
420 proxyAddress = value;
421 break;
423 case "proxydomain":
424 case "pd":
425 proxyDomain = value;
426 break;
428 case "proxypassword":
429 case "pp":
430 proxyPassword = value;
431 break;
433 case "proxyusername":
434 case "pu":
435 proxyUsername = value;
436 break;
438 case "server":
439 style = ServiceDescriptionImportStyle.Server;
440 break;
442 case "u":
443 case "username":
444 username = value;
445 break;
447 case "verbose":
448 verbose = true;
449 break;
451 case "fields":
452 options &= ~CodeGenerationOptions.GenerateProperties;
453 break;
455 case "sample":
456 sampleSoap = value;
457 break;
459 case "?":
460 help = true;
461 break;
463 default:
464 if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) {
465 urls.Add (argument);
466 break;
468 else
469 throw new Exception("Unknown option " + option);
473 DiscoveryClientProtocol CreateClient ()
475 DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();
477 if (username != null || password != null || domain != null)
479 NetworkCredential credentials = new NetworkCredential();
481 if (username != null)
482 credentials.UserName = username;
484 if (password != null)
485 credentials.Password = password;
487 if (domain != null)
488 credentials.Domain = domain;
490 dcc.Credentials = credentials;
493 if (proxyAddress != null)
495 WebProxy proxy = new WebProxy (proxyAddress);
496 if (proxyUsername != null || proxyPassword != null || proxyDomain != null)
498 NetworkCredential credentials = new NetworkCredential();
500 if (proxyUsername != null)
501 credentials.UserName = proxyUsername;
503 if (proxyPassword != null)
504 credentials.Password = proxyPassword;
506 if (proxyDomain != null)
507 credentials.Domain = proxyDomain;
509 proxy.Credentials = credentials;
513 return dcc;
516 static void WriteText (string text, int initialLeftMargin, int leftMargin)
518 int n = 0;
519 int margin = initialLeftMargin;
520 int maxCols = 80;
522 if (text == "") {
523 Console.WriteLine ();
524 return;
527 while (n < text.Length)
529 int col = margin;
530 int lastWhite = -1;
531 int sn = n;
532 while (col < maxCols && n < text.Length) {
533 if (char.IsWhiteSpace (text[n]))
534 lastWhite = n;
535 col++;
536 n++;
539 if (lastWhite == -1 || col < maxCols)
540 lastWhite = n;
541 else if (col >= maxCols)
542 n = lastWhite + 1;
544 Console.WriteLine (new String (' ', margin) + text.Substring (sn, lastWhite - sn));
545 margin = leftMargin;