2010-05-19 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / wsdl / MonoWSDL.cs
blob430b225329d1e6d533d9fd206a04752b82574306
1 ///
2 /// MonoWSDL.cs -- a WSDL to proxy code generator.
3 ///
4 /// Author: Erik LeBel (eriklebel@yahoo.ca)
5 /// Lluis Sanchez (lluis@ximian.com)
6 ///
7 /// Copyright (C) 2003, Erik LeBel,
8 ///
10 #if !NET_2_0
12 using System;
13 using System.Collections.Specialized;
14 using System.Xml;
15 using System.Xml.Schema;
16 using System.Collections;
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.Reflection;
25 using Microsoft.CSharp;
27 namespace Mono.WebServices
29 ///
30 /// <summary>
31 /// Source code generator.
32 /// </summary>
33 ///
34 class SourceGenerator
36 string applicationSiganture = null;
37 string appSettingURLKey = null;
38 string appSettingBaseURL = null;
39 string language = "CS";
40 string ns = null;
41 string outFilename = null;
42 string protocol = "Soap";
43 bool server = false;
45 ///
46 /// <summary/>
47 ///
48 public string Language
50 // FIXME validate
51 set { language = value; }
54 ///
55 /// <summary/>
56 ///
57 public string Namespace
59 set { ns = value; }
62 ///
63 /// <summary>
64 /// The file to contain the generated code.
65 /// </summary>
66 ///
67 public string Filename
69 set { outFilename = value; }
72 ///
73 /// <summary/>
74 ///
75 public string Protocol
77 // FIXME validate
78 set { protocol = value; }
79 get { return protocol; }
82 ///
83 /// <summary/>
84 ///
85 public string ApplicationSignature
87 set { applicationSiganture = value; }
90 ///
91 /// <summary/>
92 ///
93 public string AppSettingURLKey
95 set { appSettingURLKey = value; }
98 ///
99 /// <summary/>
101 public string AppSettingBaseURL
103 set { appSettingBaseURL = value; }
107 /// <summary/>
109 public bool Server
111 set { server = value; }
115 /// <summary>
116 /// Generate code for the specified ServiceDescription.
117 /// </summary>
119 public bool GenerateCode (ArrayList descriptions, ArrayList schemas)
121 // FIXME iterate over each serviceDescription.Services?
122 CodeNamespace codeNamespace = GetCodeNamespace();
123 CodeCompileUnit codeUnit = new CodeCompileUnit();
124 bool hasWarnings = false;
126 codeUnit.Namespaces.Add(codeNamespace);
128 ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
129 importer.ProtocolName = protocol;
130 if (server)
131 importer.Style = ServiceDescriptionImportStyle.Server;
133 foreach (ServiceDescription sd in descriptions)
134 importer.AddServiceDescription(sd, appSettingURLKey, appSettingBaseURL);
136 foreach (XmlSchema sc in schemas)
137 importer.Schemas.Add (sc);
139 ServiceDescriptionImportWarnings warnings = importer.Import(codeNamespace, codeUnit);
140 if (warnings != 0)
142 if ((warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)
143 Console.WriteLine ("WARNING: No proxy class was generated");
144 if ((warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)
145 Console.WriteLine ("WARNING: The proxy class generated includes no methods");
146 if ((warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)
147 Console.WriteLine ("WARNING: At least one optional extension has been ignored");
148 if ((warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)
149 Console.WriteLine ("WARNING: At least one necessary extension has been ignored");
150 if ((warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)
151 Console.WriteLine ("WARNING: At least one binding is of an unsupported type and has been ignored");
152 if ((warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)
153 Console.WriteLine ("WARNING: At least one operation is of an unsupported type and has been ignored");
154 hasWarnings = true;
157 string fileName = null;
158 bool hasBindings = false;
160 foreach (ServiceDescription desc in descriptions)
162 if (fileName == null && desc.Services.Count > 0)
163 fileName = desc.Services[0].Name;
165 if (desc.Bindings.Count > 0 || desc.Services.Count > 0)
166 hasBindings = true;
169 if (fileName == null)
170 fileName = "output";
172 if (hasBindings)
173 WriteCodeUnit (codeUnit, fileName);
175 return hasWarnings;
179 /// <summary>
180 /// Create the CodeNamespace with the generator's signature commented in.
181 /// </summary>
183 CodeNamespace GetCodeNamespace()
185 CodeNamespace codeNamespace = new CodeNamespace(ns);
187 if (applicationSiganture != null)
189 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSiganture + "\n"));
192 return codeNamespace;
196 /// <summary/>
198 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)
200 CodeDomProvider provider = GetProvider();
201 ICodeGenerator generator = provider.CreateGenerator();
202 CodeGeneratorOptions options = new CodeGeneratorOptions();
204 string filename;
205 if (outFilename != null)
206 filename = outFilename;
207 else
208 filename = serviceName + "." + provider.FileExtension;
210 Console.WriteLine ("Writing file '{0}'", filename);
211 StreamWriter writer = new StreamWriter(filename);
212 generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);
213 writer.Close();
217 /// <summary>
218 /// Fetch the Code Provider for the language specified by the 'language' members.
219 /// </summary>
221 private CodeDomProvider GetProvider()
223 CodeDomProvider provider;
224 Type type;
226 switch (language.ToUpper ()) {
227 case "CS":
228 provider = new CSharpCodeProvider ();
229 break;
230 case "VB":
231 provider = new Microsoft.VisualBasic.VBCodeProvider ();
232 break;
233 case "BOO":
234 type = Type.GetType("Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67");
235 if (type != null){
236 return (CodeDomProvider) Activator.CreateInstance (type);
238 throw new Exception ("Boo.Lang.CodeDom.BooCodeProvider not available");
240 default:
241 type = Type.GetType(language);
242 if (type != null) {
243 return (CodeDomProvider) Activator.CreateInstance (type);
245 throw new Exception ("Unknown language");
247 return provider;
252 /// <summary>
253 /// monoWSDL's main application driver. Reads the command-line arguments and dispatch the
254 /// appropriate handlers.
255 /// </summary>
257 public class Driver
259 const string ProductId = "Mono Web Services Description Language Utility";
260 const string UsageMessage =
261 "wsdl [options] {path | URL} \n\n"
262 + " -d, -domain:domain Domain of username for server authentication.\n"
263 + " -l, -language:language Language of generated code. Allowed CS (default)\n"
264 + " and VB. You can also specify the fully qualified\n"
265 + " name of a class that implements the\n"
266 + " System.CodeDom.Compiler.CodeDomProvider Class.\n"
267 + " -n, -namespace:ns The namespace of the generated code, default\n"
268 + " namespace if none.\n"
269 + " -nologo Surpress the startup logo.\n"
270 + " -o, -out:filename The target file for generated code.\n"
271 + " -p, -password:pwd Password used to contact the server.\n"
272 + " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n"
273 + " HttpGet or HttpPost.\n"
274 + " -server Generate server instead of client proxy code.\n"
275 + " -u, -username:username Username used to contact the server.\n"
276 + " -proxy:url Address of the proxy.\n"
277 + " -pu, -proxyusername:username Username used to contact the proxy.\n"
278 + " -pp, -proxypassword:pwd Password used to contact the proxy.\n"
279 + " -pd, -proxydomain:domain Domain of username for proxy authentication.\n"
280 + " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"
281 + " url for the generated WS proxy.\n"
282 + " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"
283 + " service url.\n"
284 + " -type:typename,assembly Generate a proxy for a compiled web service\n"
285 + " class. The URL parameter can be used to provide\n"
286 + " the location of the service.\n"
287 + " -sample:[binding/]operation Display a sample SOAP request and response.\n"
288 + " -? Display this message\n"
289 + "\n"
290 + "Options can be of the forms -option, --option or /option\n";
292 SourceGenerator generator = null;
294 ArrayList descriptions = new ArrayList ();
295 ArrayList schemas = new ArrayList ();
297 bool noLogo = false;
298 bool help = false;
299 bool hasURL = false;
300 string sampleSoap = null;
302 string proxyAddress = null;
303 string proxyDomain = null;
304 string proxyPassword = null;
305 string proxyUsername = null;
306 string username;
307 string password;
308 string domain;
310 StringCollection urls = new StringCollection ();
311 string className;
314 /// <summary>
315 /// Initialize the document retrieval component and the source code generator.
316 /// </summary>
318 Driver()
320 generator = new SourceGenerator();
321 generator.ApplicationSignature = ProductId;
325 /// <summary>
326 /// Interperet the command-line arguments and configure the relavent components.
327 /// </summary>
328 ///
329 void ImportArgument(string argument)
331 string optionValuePair;
333 if (argument.StartsWith("--"))
335 optionValuePair = argument.Substring(2);
337 else if (argument.StartsWith("/") || argument.StartsWith("-"))
339 optionValuePair = argument.Substring(1);
341 else
343 hasURL = true;
344 urls.Add (argument);
345 return;
348 string option;
349 string value;
351 int indexOfEquals = optionValuePair.IndexOf(':');
352 if (indexOfEquals > 0)
354 option = optionValuePair.Substring(0, indexOfEquals);
355 value = optionValuePair.Substring(indexOfEquals + 1);
357 else
359 option = optionValuePair;
360 value = null;
363 switch (option)
365 case "appsettingurlkey":
366 case "urlkey":
367 generator.AppSettingURLKey = value;
368 break;
370 case "appsettingbaseurl":
371 case "baseurl":
372 generator.AppSettingBaseURL = value;
373 break;
375 case "d":
376 case "domain":
377 domain = value;
378 break;
380 case "l":
381 case "language":
382 generator.Language = value;
383 break;
385 case "n":
386 case "namespace":
387 generator.Namespace = value;
388 break;
390 case "nologo":
391 noLogo = true;
392 break;
394 case "o":
395 case "out":
396 generator.Filename = value;
397 break;
399 case "p":
400 case "password":
401 password = value;
402 break;
404 case "protocol":
405 generator.Protocol = value;
406 break;
408 case "proxy":
409 proxyAddress = value;
410 break;
412 case "proxydomain":
413 case "pd":
414 proxyDomain = value;
415 break;
417 case "proxypassword":
418 case "pp":
419 proxyPassword = value;
420 break;
422 case "proxyusername":
423 case "pu":
424 proxyUsername = value;
425 break;
427 case "server":
428 generator.Server = true;
429 break;
431 case "u":
432 case "username":
433 username = value;
434 break;
436 case "sample":
437 sampleSoap = value;
438 break;
440 case "type":
441 case "t":
442 className = value;
443 break;
445 case "?":
446 help = true;
447 break;
449 default:
450 if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) {
451 hasURL = true;
452 urls.Add (argument);
453 break;
455 else
456 throw new Exception("Unknown option '" + option + "'");
460 DiscoveryClientProtocol CreateClient ()
462 DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();
464 if (username != null || password != null || domain != null)
466 NetworkCredential credentials = new NetworkCredential();
468 if (username != null)
469 credentials.UserName = username;
471 if (password != null)
472 credentials.Password = password;
474 if (domain != null)
475 credentials.Domain = domain;
477 dcc.Credentials = credentials;
480 if (proxyAddress != null)
482 WebProxy proxy = new WebProxy (proxyAddress);
483 if (proxyUsername != null || proxyPassword != null || proxyDomain != null)
485 NetworkCredential credentials = new NetworkCredential();
487 if (proxyUsername != null)
488 credentials.UserName = proxyUsername;
490 if (proxyPassword != null)
491 credentials.Password = proxyPassword;
493 if (proxyDomain != null)
494 credentials.Domain = proxyDomain;
496 proxy.Credentials = credentials;
500 return dcc;
504 /// <summary>
505 /// Driver's main control flow:
506 /// - parse arguments
507 /// - report required messages
508 /// - terminate if no input
509 /// - report errors
510 /// </summary>
512 int Run(string[] args)
516 // parse command line arguments
517 foreach (string argument in args)
519 ImportArgument(argument);
522 if (noLogo == false)
523 Console.WriteLine(ProductId);
525 if (help || (!hasURL && className == null))
527 Console.WriteLine(UsageMessage);
528 return 0;
531 if (className == null) {
532 DiscoveryClientProtocol dcc = CreateClient ();
534 foreach (string urlEntry in urls) {
535 string url = urlEntry;
536 dcc.AllowAutoRedirect = true;
537 if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://"))
538 url = new Uri (Path.GetFullPath (url)).ToString ();
540 dcc.DiscoverAny (url);
541 dcc.ResolveAll ();
544 foreach (object doc in dcc.Documents.Values) {
545 if (doc is ServiceDescription)
546 descriptions.Add ((ServiceDescription) doc);
547 else if (doc is XmlSchema)
548 schemas.Add ((XmlSchema) doc);
551 if (descriptions.Count == 0) {
552 Console.WriteLine ("Warning: no classes were generated.");
553 return 0;
555 } else {
556 string[] names = className.Split (',');
557 if (names.Length != 2) throw new Exception ("Invalid parameter value for 'type'");
558 string cls = names[0].Trim ();
559 string assembly = names[1].Trim ();
561 Assembly asm = Assembly.LoadFrom (assembly);
562 Type t = asm.GetType (cls);
563 if (t == null) throw new Exception ("Type '" + cls + "' not found in assembly " + assembly);
564 ServiceDescriptionReflector reflector = new ServiceDescriptionReflector ();
565 foreach (string url in urls)
566 reflector.Reflect (t, url);
567 foreach (XmlSchema s in reflector.Schemas)
568 schemas.Add (s);
570 foreach (ServiceDescription sd in reflector.ServiceDescriptions)
571 descriptions.Add (sd);
574 if (sampleSoap != null)
576 ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, generator.Protocol);
577 return 0;
580 // generate the code
581 generator.GenerateCode (descriptions, schemas);
582 return 0;
584 catch (NullReferenceException e)
586 Console.WriteLine (e);
587 return 2;
589 catch (InvalidCastException e)
591 Console.WriteLine (e);
592 return 2;
594 catch (Exception exception)
596 Console.WriteLine("Error: {0}", exception.Message);
597 // FIXME: surpress this except for when debug is enabled
598 //Console.WriteLine("Stack:\n {0}", exception.StackTrace);
599 return 2;
604 /// <summary>
605 /// Application entry point.
606 /// </summary>
608 public static int Main(string[] args)
610 Driver d = new Driver();
611 return d.Run(args);
616 #endif