2010-05-25 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / wsdl / MonoWSDL2.cs
blobf1345bd03b64ccd58e279a6262703662e286326f
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 ///
10 #if NET_2_0
12 using System;
13 using System.Xml;
14 using System.Xml.Serialization;
15 using System.Xml.Schema;
16 using System.Collections;
17 using System.Collections.Specialized;
18 using System.CodeDom;
19 using System.CodeDom.Compiler;
20 using System.IO;
21 using System.Net;
22 using System.Web.Services.Description;
23 using System.Web.Services.Discovery;
24 using System.Web.Services;
26 using Microsoft.CSharp;
28 namespace Mono.WebServices
30 public class Driver
32 string ProductId = "Web Services Description Language Utility\nMono Framework v" + Environment.Version;
33 const string UsageMessage =
34 "wsdl [options] {path | URL} {path | URL} ...\n\n"
35 + " -d, -domain:domain Domain of username for server authentication.\n"
36 + " -l, -language:language Language of generated code. Allowed CS (default)\n"
37 + " and VB. You can also specify the fully qualified\n"
38 + " name of a class that implements the\n"
39 + " System.CodeDom.Compiler.CodeDomProvider Class.\n"
40 + " -n, -namespace:ns The namespace of the generated code, default\n"
41 + " namespace if none.\n"
42 + " -nologo Surpress the startup logo.\n"
43 + " -o, -out:filename The target file for generated code.\n"
44 + " -p, -password:pwd Password used to contact the server.\n"
45 + " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n"
46 + " HttpGet or HttpPost.\n"
47 + " -fields Generate fields instead of properties in data\n"
48 + " classes.\n"
49 + " -server Generate server instead of client proxy code.\n"
50 + " -u, -username:username Username used to contact the server.\n"
51 + " -proxy:url Address of the proxy.\n"
52 + " -pu, -proxyusername:username Username used to contact the proxy.\n"
53 + " -pp, -proxypassword:pwd Password used to contact the proxy.\n"
54 + " -pd, -proxydomain:domain Domain of username for proxy authentication.\n"
55 + " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"
56 + " url for the generated WS proxy.\n"
57 + " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"
58 + " service url.\n"
59 + " -sample:[binding/]operation Display a sample SOAP request and response.\n"
60 + " -? Display this message\n"
61 + "\n"
62 + "Options can be of the forms -option, --option or /option\n";
64 ArrayList descriptions = new ArrayList ();
65 ArrayList schemas = new ArrayList ();
67 bool noLogo;
68 bool help;
69 string sampleSoap;
71 string proxyAddress;
72 string proxyDomain;
73 string proxyPassword;
74 string proxyUsername;
75 string username;
76 string password;
77 string domain;
79 string applicationSignature;
80 string appSettingURLKey;
81 string appSettingBaseURL;
82 string language = "CS";
83 string ns;
84 string outFilename;
85 string protocol = "Soap";
86 ServiceDescriptionImportStyle style;
87 CodeGenerationOptions options = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
88 bool verbose;
90 StringCollection urls = new StringCollection ();
92 ///
93 /// <summary>
94 /// Application entry point.
95 /// </summary>
96 ///
97 public static int Main(string[] args)
99 Driver d = new Driver();
100 return d.Run(args);
103 Driver()
105 applicationSignature = ProductId;
108 int Run (string[] args)
112 // parse command line arguments
113 foreach (string argument in args)
114 ImportArgument(argument);
116 if (noLogo == false)
117 Console.WriteLine(ProductId);
119 if (help || urls.Count == 0)
121 Console.WriteLine(UsageMessage);
122 return 0;
125 CodeCompileUnit codeUnit = new CodeCompileUnit();
126 CodeNamespace proxyCode = GetCodeNamespace();
127 codeUnit.Namespaces.Add (proxyCode);
129 WebReferenceCollection references = new WebReferenceCollection ();
131 DiscoveryClientProtocol dcc = CreateClient ();
133 foreach (string murl in urls)
136 string url = murl;
137 if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://"))
138 url = new Uri (Path.GetFullPath (url)).ToString ();
140 dcc.DiscoverAny (url);
141 dcc.ResolveAll ();
145 WebReference reference = new WebReference (dcc.Documents, proxyCode, protocol, appSettingURLKey, appSettingBaseURL);
146 references.Add (reference);
148 if (sampleSoap != null)
149 ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, protocol);
151 if (sampleSoap != null)
152 return 0;
154 // generate the code
155 GenerateCode (references, codeUnit);
156 return 0;
158 catch (Exception exception)
160 Console.WriteLine("Error: {0}", exception.Message);
162 // Supress this except for when debug is enabled
163 Console.WriteLine("Stack:\n {0}", exception.StackTrace);
164 return 2;
169 /// <summary>
170 /// Generate code for the specified ServiceDescription.
171 /// </summary>
173 public bool GenerateCode (WebReferenceCollection references, CodeCompileUnit codeUnit)
175 bool hasWarnings = false;
177 CodeDomProvider provider = GetProvider();
179 StringCollection validationWarnings;
180 WebReferenceOptions opts = new WebReferenceOptions ();
181 opts.CodeGenerationOptions = options;
182 opts.Style = style;
183 opts.Verbose = verbose;
184 validationWarnings = ServiceDescriptionImporter.GenerateWebReferences (references, provider, codeUnit, opts);
186 for (int n=0; n<references.Count; n++)
188 WebReference wr = references [n];
190 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
191 if (String.Compare (protocol, "SOAP", StringComparison.OrdinalIgnoreCase) == 0 && !WebServicesInteroperability.CheckConformance (WsiProfiles.BasicProfile1_1, wr, violations)) {
192 wr.Warnings |= ServiceDescriptionImportWarnings.WsiConformance;
195 if (wr.Warnings != 0)
197 if (!hasWarnings) {
198 WriteText ("", 0, 0);
199 WriteText ("There where some warnings while generating the code:", 0, 0);
202 WriteText ("", 0, 0);
203 WriteText (urls[n], 2, 2);
205 if ((wr.Warnings & ServiceDescriptionImportWarnings.WsiConformance) > 0) {
206 WriteText ("- This web reference does not conform to WS-I Basic Profile v1.1", 4, 6);
207 foreach (BasicProfileViolation vio in violations) {
208 WriteText (vio.NormativeStatement + ": " + vio.Details, 8, 8);
209 foreach (string ele in vio.Elements)
210 WriteText ("* " + ele, 10, 12);
214 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)
215 WriteText ("- WARNING: No proxy class was generated", 4, 6);
216 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)
217 WriteText ("- WARNING: The proxy class generated includes no methods", 4, 6);
218 if ((wr.Warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)
219 WriteText ("- WARNING: At least one optional extension has been ignored", 4, 6);
220 if ((wr.Warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)
221 WriteText ("- WARNING: At least one necessary extension has been ignored", 4, 6);
222 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)
223 WriteText ("- WARNING: At least one binding is of an unsupported type and has been ignored", 4, 6);
224 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)
225 WriteText ("- WARNING: At least one operation is of an unsupported type and has been ignored", 4, 6);
227 hasWarnings = true;
231 if (hasWarnings) WriteText ("",0,0);
233 string filename = outFilename;
234 bool hasBindings = false;
236 foreach (object doc in references[0].Documents.Values)
238 ServiceDescription desc = doc as ServiceDescription;
239 if (desc == null) continue;
241 if (desc.Services.Count > 0 && filename == null)
242 filename = desc.Services[0].Name + "." + provider.FileExtension;
244 if (desc.Bindings.Count > 0 || desc.Services.Count > 0)
245 hasBindings = true;
248 if (filename == null)
249 filename = "output." + provider.FileExtension;
251 if (hasBindings) {
252 WriteText ("Writing file '" + filename + "'", 0, 0);
253 StreamWriter writer = new StreamWriter(filename);
255 CodeGeneratorOptions compilerOptions = new CodeGeneratorOptions();
256 provider.GenerateCodeFromCompileUnit (codeUnit, writer, compilerOptions);
257 writer.Close();
260 return hasWarnings;
264 /// <summary>
265 /// Create the CodeNamespace with the generator's signature commented in.
266 /// </summary>
268 CodeNamespace GetCodeNamespace()
270 CodeNamespace codeNamespace = new CodeNamespace(ns);
272 if (applicationSignature != null)
274 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSignature + "\n"));
277 return codeNamespace;
281 /// <summary/>
283 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)
285 CodeDomProvider provider = GetProvider();
286 ICodeGenerator generator = provider.CreateGenerator();
287 CodeGeneratorOptions options = new CodeGeneratorOptions();
289 string filename;
290 if (outFilename != null)
291 filename = outFilename;
292 else
293 filename = serviceName + "." + provider.FileExtension;
295 Console.WriteLine ("Writing file '{0}'", filename);
296 StreamWriter writer = new StreamWriter(filename);
297 generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);
298 writer.Close();
302 /// <summary>
303 /// Fetch the Code Provider for the language specified by the 'language' members.
304 /// </summary>
306 private CodeDomProvider GetProvider()
308 CodeDomProvider provider;
309 Type type;
311 switch (language.ToUpper ()) {
312 case "CS":
313 provider = new CSharpCodeProvider ();
314 break;
315 case "VB":
316 provider = new Microsoft.VisualBasic.VBCodeProvider ();
317 break;
318 case "BOO":
319 type = Type.GetType("Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67");
320 if (type != null){
321 return (CodeDomProvider) Activator.CreateInstance (type);
323 throw new Exception ("Boo.Lang.CodeDom.BooCodeProvider not available");
325 default:
326 type = Type.GetType(language);
327 if (type != null) {
328 return (CodeDomProvider) Activator.CreateInstance (type);
330 throw new Exception ("Unknown language");
332 return provider;
338 /// <summary>
339 /// Interperet the command-line arguments and configure the relavent components.
340 /// </summary>
341 ///
342 void ImportArgument(string argument)
344 string optionValuePair;
346 if (argument.StartsWith("--"))
348 optionValuePair = argument.Substring(2);
350 else if (argument.StartsWith("/") || argument.StartsWith("-"))
352 optionValuePair = argument.Substring(1);
354 else
356 urls.Add (argument);
357 return;
360 string option;
361 string value;
363 int indexOfEquals = optionValuePair.IndexOf(':');
364 if (indexOfEquals > 0)
366 option = optionValuePair.Substring(0, indexOfEquals);
367 value = optionValuePair.Substring(indexOfEquals + 1);
369 else
371 option = optionValuePair;
372 value = null;
375 switch (option)
377 case "appsettingurlkey":
378 case "urlkey":
379 appSettingURLKey = value;
380 break;
382 case "appsettingbaseurl":
383 case "baseurl":
384 appSettingBaseURL = value;
385 break;
387 case "d":
388 case "domain":
389 domain = value;
390 break;
392 case "l":
393 case "language":
394 language = value;
395 break;
397 case "n":
398 case "namespace":
399 ns = value;
400 break;
402 case "nologo":
403 noLogo = true;
404 break;
406 case "o":
407 case "out":
408 outFilename = value;
409 break;
411 case "p":
412 case "password":
413 password = value;
414 break;
416 case "protocol":
417 protocol = value;
418 break;
420 case "proxy":
421 proxyAddress = value;
422 break;
424 case "proxydomain":
425 case "pd":
426 proxyDomain = value;
427 break;
429 case "proxypassword":
430 case "pp":
431 proxyPassword = value;
432 break;
434 case "proxyusername":
435 case "pu":
436 proxyUsername = value;
437 break;
439 case "server":
440 style = ServiceDescriptionImportStyle.Server;
441 break;
443 case "u":
444 case "username":
445 username = value;
446 break;
448 case "verbose":
449 verbose = true;
450 break;
452 case "fields":
453 options &= ~CodeGenerationOptions.GenerateProperties;
454 break;
456 case "sample":
457 sampleSoap = value;
458 break;
460 case "?":
461 help = true;
462 break;
464 default:
465 if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) {
466 urls.Add (argument);
467 break;
469 else
470 throw new Exception("Unknown option " + option);
474 DiscoveryClientProtocol CreateClient ()
476 DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();
478 if (username != null || password != null || domain != null)
480 NetworkCredential credentials = new NetworkCredential();
482 if (username != null)
483 credentials.UserName = username;
485 if (password != null)
486 credentials.Password = password;
488 if (domain != null)
489 credentials.Domain = domain;
491 dcc.Credentials = credentials;
494 if (proxyAddress != null)
496 WebProxy proxy = new WebProxy (proxyAddress);
497 if (proxyUsername != null || proxyPassword != null || proxyDomain != null)
499 NetworkCredential credentials = new NetworkCredential();
501 if (proxyUsername != null)
502 credentials.UserName = proxyUsername;
504 if (proxyPassword != null)
505 credentials.Password = proxyPassword;
507 if (proxyDomain != null)
508 credentials.Domain = proxyDomain;
510 proxy.Credentials = credentials;
514 return dcc;
517 static void WriteText (string text, int initialLeftMargin, int leftMargin)
519 int n = 0;
520 int margin = initialLeftMargin;
521 int maxCols = 80;
523 if (text == "") {
524 Console.WriteLine ();
525 return;
528 while (n < text.Length)
530 int col = margin;
531 int lastWhite = -1;
532 int sn = n;
533 while (col < maxCols && n < text.Length) {
534 if (char.IsWhiteSpace (text[n]))
535 lastWhite = n;
536 col++;
537 n++;
540 if (lastWhite == -1 || col < maxCols)
541 lastWhite = n;
542 else if (col >= maxCols)
543 n = lastWhite + 1;
545 Console.WriteLine (new String (' ', margin) + text.Substring (sn, lastWhite - sn));
546 margin = leftMargin;
552 #endif