**** Merged from MCS ****
[mono-project.git] / mcs / tools / wsdl / MonoWSDL2.cs
blobe7aa82b123e6a04428f23be9b5b4c76c01f6c272
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 using System;
11 using System.Xml;
12 using System.Xml.Serialization;
13 using System.Xml.Schema;
14 using System.Collections;
15 using System.Collections.Specialized;
16 using System.CodeDom;
17 using System.CodeDom.Compiler;
18 using System.IO;
19 using System.Net;
20 using System.Web.Services.Description;
21 using System.Web.Services.Discovery;
22 using System.Web.Services;
24 using Microsoft.CSharp;
26 namespace Mono.WebServices
28 public class Driver
30 string ProductId = "Web Services Description Language Utility\nMono Framework v" + Environment.Version;
31 const string UsageMessage =
32 "wsdl [options] {path | URL} {path | URL} ...\n\n"
33 + " -d, -domain:domain Domain of username for server authentication.\n"
34 + " -l, -language:language Language of generated code. Allowed CS (default)\n"
35 + " and VB.\n"
36 + " -n, -namespace:ns The namespace of the generated code, default\n"
37 + " namespace if none.\n"
38 + " -nologo Surpress the startup logo.\n"
39 + " -o, -out:filename The target file for generated code.\n"
40 + " -p, -password:pwd Password used to contact the server.\n"
41 + " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n"
42 + " HttpGet or HttpPost.\n"
43 + " -fields Generate fields instead of properties in data\n"
44 + " classes.\n"
45 + " -server Generate server instead of client proxy code.\n"
46 + " -u, -username:username Username used to contact the server.\n"
47 + " -proxy:url Address of the proxy.\n"
48 + " -pu, -proxyusername:username Username used to contact the proxy.\n"
49 + " -pp, -proxypassword:pwd Password used to contact the proxy.\n"
50 + " -pd, -proxydomain:domain Domain of username for proxy authentication.\n"
51 + " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"
52 + " url for the generated WS proxy.\n"
53 + " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"
54 + " service url.\n"
55 + " -sample:[binding/]operation Display a sample SOAP request and response.\n"
56 + " -? Display this message\n"
57 + "\n"
58 + "Options can be of the forms -option, --option or /option\n";
60 ArrayList descriptions = new ArrayList ();
61 ArrayList schemas = new ArrayList ();
63 bool noLogo;
64 bool help;
65 string sampleSoap;
67 string proxyAddress;
68 string proxyDomain;
69 string proxyPassword;
70 string proxyUsername;
71 string username;
72 string password;
73 string domain;
75 string applicationSignature;
76 string appSettingURLKey;
77 string appSettingBaseURL;
78 string language = "CS";
79 string ns;
80 string outFilename;
81 string protocol = "Soap";
82 ServiceDescriptionImportStyle style;
83 CodeGenerationOptions options = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
84 bool verbose;
86 StringCollection urls = new StringCollection ();
88 ///
89 /// <summary>
90 /// Application entry point.
91 /// </summary>
92 ///
93 public static int Main(string[] args)
95 Driver d = new Driver();
96 return d.Run(args);
99 Driver()
101 applicationSignature = ProductId;
104 int Run (string[] args)
108 // parse command line arguments
109 foreach (string argument in args)
110 ImportArgument(argument);
112 if (noLogo == false)
113 Console.WriteLine(ProductId);
115 if (help || urls.Count == 0)
117 Console.WriteLine(UsageMessage);
118 return 0;
121 CodeCompileUnit codeUnit = new CodeCompileUnit();
122 CodeNamespace proxyCode = GetCodeNamespace();
123 codeUnit.Namespaces.Add (proxyCode);
125 WebReferenceCollection references = new WebReferenceCollection ();
126 foreach (string murl in urls)
128 DiscoveryClientProtocol dcc = CreateClient ();
130 string url = murl;
131 if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://"))
132 url = "file://" + Path.GetFullPath (url);
134 dcc.DiscoverAny (url);
135 dcc.ResolveAll ();
137 WebReference reference = new WebReference (dcc.Documents, proxyCode, protocol, appSettingURLKey, appSettingBaseURL);
138 references.Add (reference);
140 if (sampleSoap != null)
141 ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, protocol);
144 if (sampleSoap != null)
145 return 0;
147 // generate the code
148 if (GenerateCode (references, codeUnit))
149 return 1;
150 else
151 return 0;
153 catch (Exception exception)
155 Console.WriteLine("Error: {0}", exception.Message);
157 // Supress this except for when debug is enabled
158 Console.WriteLine("Stack:\n {0}", exception.StackTrace);
159 return 2;
164 /// <summary>
165 /// Generate code for the specified ServiceDescription.
166 /// </summary>
168 public bool GenerateCode (WebReferenceCollection references, CodeCompileUnit codeUnit)
170 bool hasWarnings = false;
172 CodeDomProvider provider = GetProvider();
173 ICodeGenerator generator = provider.CreateGenerator();
175 StringCollection validationWarnings;
176 validationWarnings = ServiceDescriptionImporter.GenerateWebReferences (references, options, style, generator, codeUnit, verbose);
178 for (int n=0; n<references.Count; n++)
180 WebReference wr = references [n];
182 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
183 if (!WebServicesInteroperability.CheckConformance (WsiClaims.BP10, wr, violations)) {
184 wr.Warnings |= ServiceDescriptionImportWarnings.WsiConformance;
187 if (wr.Warnings != 0)
189 if (!hasWarnings) {
190 WriteText ("", 0, 0);
191 WriteText ("There where some warnings while generating the code:", 0, 0);
194 WriteText ("", 0, 0);
195 WriteText (urls[n], 2, 2);
197 if ((wr.Warnings & ServiceDescriptionImportWarnings.WsiConformance) > 0) {
198 WriteText ("- This web reference does not conform to WS-I Basic Profile v1.0", 4, 6);
199 foreach (BasicProfileViolation vio in violations) {
200 WriteText (vio.NormativeStatement + ": " + vio.Details, 8, 8);
201 foreach (string ele in vio.Elements)
202 WriteText ("* " + ele, 10, 12);
206 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)
207 WriteText ("- WARNING: No proxy class was generated", 4, 6);
208 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)
209 WriteText ("- WARNING: The proxy class generated includes no methods", 4, 6);
210 if ((wr.Warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)
211 WriteText ("- WARNING: At least one optional extension has been ignored", 4, 6);
212 if ((wr.Warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)
213 WriteText ("- WARNING: At least one necessary extension has been ignored", 4, 6);
214 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)
215 WriteText ("- WARNING: At least one binding is of an unsupported type and has been ignored", 4, 6);
216 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)
217 WriteText ("- WARNING: At least one operation is of an unsupported type and has been ignored", 4, 6);
219 hasWarnings = true;
223 if (hasWarnings) WriteText ("",0,0);
225 string filename = outFilename;
226 bool hasBindings = false;
228 foreach (object doc in references[0].Documents.Values)
230 ServiceDescription desc = doc as ServiceDescription;
231 if (desc == null) continue;
233 if (desc.Services.Count > 0 && filename == null)
234 filename = desc.Services[0].Name + "." + provider.FileExtension;
236 if (desc.Bindings.Count > 0 || desc.Services.Count > 0)
237 hasBindings = true;
240 if (filename == null)
241 filename = "output." + provider.FileExtension;
243 if (hasBindings) {
244 WriteText ("Writing file '" + filename + "'", 0, 0);
245 StreamWriter writer = new StreamWriter(filename);
247 CodeGeneratorOptions compilerOptions = new CodeGeneratorOptions();
248 generator.GenerateCodeFromCompileUnit (codeUnit, writer, compilerOptions);
249 writer.Close();
252 return hasWarnings;
256 /// <summary>
257 /// Create the CodeNamespace with the generator's signature commented in.
258 /// </summary>
260 CodeNamespace GetCodeNamespace()
262 CodeNamespace codeNamespace = new CodeNamespace(ns);
264 if (applicationSignature != null)
266 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSignature + "\n"));
269 return codeNamespace;
273 /// <summary/>
275 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)
277 CodeDomProvider provider = GetProvider();
278 ICodeGenerator generator = provider.CreateGenerator();
279 CodeGeneratorOptions options = new CodeGeneratorOptions();
281 string filename;
282 if (outFilename != null)
283 filename = outFilename;
284 else
285 filename = serviceName + "." + provider.FileExtension;
287 Console.WriteLine ("Writing file '{0}'", filename);
288 StreamWriter writer = new StreamWriter(filename);
289 generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);
290 writer.Close();
294 /// <summary>
295 /// Fetch the Code Provider for the language specified by the 'language' members.
296 /// </summary>
298 private CodeDomProvider GetProvider()
300 // FIXME these should be loaded dynamically using reflection
301 CodeDomProvider provider;
303 switch (language.ToUpper())
305 case "CS":
306 provider = new CSharpCodeProvider();
307 break;
309 case "VB":
310 provider = new Microsoft.VisualBasic.VBCodeProvider();
311 break;
313 default:
314 throw new Exception("Unknow language");
317 return provider;
323 /// <summary>
324 /// Interperet the command-line arguments and configure the relavent components.
325 /// </summary>
326 ///
327 void ImportArgument(string argument)
329 string optionValuePair;
331 if (argument.StartsWith("--"))
333 optionValuePair = argument.Substring(2);
335 else if (argument.StartsWith("/") || argument.StartsWith("-"))
337 optionValuePair = argument.Substring(1);
339 else
341 urls.Add (argument);
342 return;
345 string option;
346 string value;
348 int indexOfEquals = optionValuePair.IndexOf(':');
349 if (indexOfEquals > 0)
351 option = optionValuePair.Substring(0, indexOfEquals);
352 value = optionValuePair.Substring(indexOfEquals + 1);
354 else
356 option = optionValuePair;
357 value = null;
360 switch (option)
362 case "appsettingurlkey":
363 case "urlkey":
364 appSettingURLKey = value;
365 break;
367 case "appsettingbaseurl":
368 case "baseurl":
369 appSettingBaseURL = value;
370 break;
372 case "d":
373 case "domain":
374 domain = value;
375 break;
377 case "l":
378 case "language":
379 language = value;
380 break;
382 case "n":
383 case "namespace":
384 ns = value;
385 break;
387 case "nologo":
388 noLogo = true;
389 break;
391 case "o":
392 case "out":
393 outFilename = value;
394 break;
396 case "p":
397 case "password":
398 password = value;
399 break;
401 case "protocol":
402 protocol = value;
403 break;
405 case "proxy":
406 proxyAddress = value;
407 break;
409 case "proxydomain":
410 case "pd":
411 proxyDomain = value;
412 break;
414 case "proxypassword":
415 case "pp":
416 proxyPassword = value;
417 break;
419 case "proxyusername":
420 case "pu":
421 proxyUsername = value;
422 break;
424 case "server":
425 style = ServiceDescriptionImportStyle.Server;
426 break;
428 case "u":
429 case "username":
430 username = value;
431 break;
433 case "verbose":
434 verbose = true;
435 break;
437 case "fields":
438 options &= ~CodeGenerationOptions.GenerateProperties;
439 break;
441 case "sample":
442 sampleSoap = value;
443 break;
445 case "?":
446 help = true;
447 break;
449 default:
450 if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) {
451 urls.Add (argument);
452 break;
454 else
455 throw new Exception("Unknown option " + option);
459 DiscoveryClientProtocol CreateClient ()
461 DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();
463 if (username != null || password != null || domain != null)
465 NetworkCredential credentials = new NetworkCredential();
467 if (username != null)
468 credentials.UserName = username;
470 if (password != null)
471 credentials.Password = password;
473 if (domain != null)
474 credentials.Domain = domain;
476 dcc.Credentials = credentials;
479 if (proxyAddress != null)
481 WebProxy proxy = new WebProxy (proxyAddress);
482 if (proxyUsername != null || proxyPassword != null || proxyDomain != null)
484 NetworkCredential credentials = new NetworkCredential();
486 if (proxyUsername != null)
487 credentials.UserName = proxyUsername;
489 if (proxyPassword != null)
490 credentials.Password = proxyPassword;
492 if (proxyDomain != null)
493 credentials.Domain = proxyDomain;
495 proxy.Credentials = credentials;
499 return dcc;
502 static void WriteText (string text, int initialLeftMargin, int leftMargin)
504 int n = 0;
505 int margin = initialLeftMargin;
506 int maxCols = 80;
508 if (text == "") {
509 Console.WriteLine ();
510 return;
513 while (n < text.Length)
515 int col = margin;
516 int lastWhite = -1;
517 int sn = n;
518 while (col < maxCols && n < text.Length) {
519 if (char.IsWhiteSpace (text[n]))
520 lastWhite = n;
521 col++;
522 n++;
525 if (lastWhite == -1 || col < maxCols)
526 lastWhite = n;
527 else if (col >= maxCols)
528 n = lastWhite + 1;
530 Console.WriteLine (new String (' ', margin) + text.Substring (sn, lastWhite - sn));
531 margin = leftMargin;