Source code: org/apache/axis/tools/ant/wsdl/Wsdl2javaAntTask.java
1 /*
2 * Copyright 2001-2002,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.apache.axis.tools.ant.wsdl;
17
18 import java.io.File;
19 import java.io.IOException;
20 import java.net.Authenticator;
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24
25 import org.apache.axis.constants.Scope;
26 import org.apache.axis.utils.DefaultAuthenticator;
27 import org.apache.axis.utils.ClassUtils;
28 import org.apache.axis.wsdl.toJava.Emitter;
29 import org.apache.axis.wsdl.toJava.FactoryProperty;
30 import org.apache.axis.wsdl.toJava.NamespaceSelector;
31 import org.apache.tools.ant.BuildException;
32 import org.apache.tools.ant.Project;
33 import org.apache.tools.ant.Task;
34 import org.apache.tools.ant.AntClassLoader;
35 import org.apache.tools.ant.types.Path;
36 import org.apache.tools.ant.types.CommandlineJava;
37 import org.apache.tools.ant.types.Environment;
38
39 /*
40 * IMPORTANT: see Java2WsdlAntTask on how to javadoc this task and rebuild
41 * the task documentation afterwards
42 *
43 */
44
45 /**
46 * Create Java classes from local or remote WSDL.
47 * Mappings from namespaces to packages can be provided as nested <mapping>
48 * elements.
49 * <p>
50 * Proxy settings are taken from the java runtime settings of http.ProxyHost,
51 * http.ProxyPort, etc. The Ant task <setProxy> can set these.
52 * As well as the nested mapping elements, this task uses the file
53 * <tt>NStoPkg.properties</tt> in the project base directory
54 * for namespace mapping
55 * <p>
56 * This task does no dependency checking; files are generated whether they
57 * need to be or not. The exception to this is the Impl class, which is
58 * not overwritten if it exists. This is a safety measure. However, all other
59 * classes are generated overwriting anything that exists.
60 * <p>
61 * The safe way to use this task is to have it generate the java source in
62 * a build directory, then have a <copy> task selectively copy the
63 * files you need into a safe location. Again, copying into the source tree
64 * is dangerous, but a separate build/src tree is safe. Then include this
65 * separate tree in the <javac> task's src attribute to include it in the
66 * build. Implement your own implementation classes of the server stub and the
67 * test cases using the generated templates.
68 * If you want to add methods to autogenerated data types, consider subclassing
69 * them, or write helper classes.
70 * <p>
71 * Tip: if you <get> the wsdl, and use the <filesmatch> condition
72 * to compare the fetched wsdl with a catched copy, you can make the target that
73 * calls the axis-wsd2ljava task conditional on the WSDL having changed. This stops
74 * spurious code regeneration and follow-on rebuilds across the java source tree.
75 * @ant.task category="axis" name="axis-wsdl2java"
76 * @author Davanum Srinivas (dims@yahoo.com)
77 * @author steve loughran
78 */
79 public class Wsdl2javaAntTask extends Task
80 {
81 private boolean verbose = false;
82 private boolean debug = false;
83 private boolean quiet = false;
84 private boolean server = false;
85 private boolean skeletonDeploy = false;
86 private boolean testCase = false;
87 private boolean noImports = false;
88 private boolean all = false;
89 private boolean helperGen = false;
90 private boolean noWrapped = false;
91 private boolean allowInvalidURL = false;
92 private String factory = null;
93 private HashMap namespaceMap = new HashMap();
94 private String output = ".";
95 private String protocolHandlerPkgs = "";
96 private String deployScope = "";
97 private String url = "";
98 private String typeMappingVersion = "1.2";
99 private long timeout = 45000;
100 private File namespaceMappingFile = null;
101 private MappingSet mappings = new MappingSet();
102 private String username = null;
103 private String password = null;
104 private Path classpath = null;
105 private List nsIncludes = new ArrayList();
106 private List nsExcludes = new ArrayList();
107 private List properties = new ArrayList();
108 private String implementationClassName = null;
109 private CommandlineJava commandline = new CommandlineJava();
110
111 /**
112 * do we print a stack trace when something goes wrong?
113 */
114 private boolean printStackTraceOnFailure = true;
115 /**
116 * what action to take when there was a failure and the source was some
117 * URL
118 */
119 private boolean failOnNetworkErrors = false;
120
121 private boolean wrapArrays = false;
122
123 public Wsdl2javaAntTask() {
124 }
125
126 /**
127 * validation code
128 * @throws BuildException if validation failed
129 */
130 protected void validate()
131 throws BuildException {
132 if (url == null || url.length() == 0) {
133 throw new BuildException("No url specified");
134 }
135 if (timeout < -1) {
136 throw new BuildException("negative timeout supplied");
137 }
138 File outdir = new File(output);
139 if (!outdir.isDirectory() || !outdir.exists()) {
140 throw new BuildException("output directory is not valid");
141 }
142 if (quiet) {
143 if (verbose) {
144 throw new BuildException("quiet and verbose options are " +
145 "exclusive");
146 }
147 if (debug) {
148 throw new BuildException("quiet and debug options are " +
149 "exclusive");
150 }
151 }
152 }
153
154 /**
155 * trace out parameters
156 * @param logLevel to log at
157 * @see org.apache.tools.ant.Project#log
158 */
159 public void traceParams(int logLevel) {
160 log("Running Wsdl2javaAntTask with parameters:", logLevel);
161 log("\tverbose:" + verbose, logLevel);
162 log("\tdebug:" + debug, logLevel);
163 log("\tquiet:" + quiet, logLevel);
164 log("\tserver-side:" + server, logLevel);
165 log("\tskeletonDeploy:" + skeletonDeploy, logLevel);
166 log("\thelperGen:" + helperGen, logLevel);
167 log("\tfactory:" + factory, logLevel);
168 log("\tnsIncludes:" + nsIncludes, logLevel);
169 log("\tnsExcludes:" + nsExcludes, logLevel);
170 log("\tfactoryProps:" + properties, logLevel);
171 log("\ttestCase:" + testCase, logLevel);
172 log("\tnoImports:" + noImports, logLevel);
173 log("\tNStoPkg:" + namespaceMap, logLevel);
174 log("\toutput:" + output, logLevel);
175 log("\tprotocolHandlerPkgs:" + protocolHandlerPkgs, logLevel);
176 log("\tdeployScope:" + deployScope, logLevel);
177 log("\tURL:" + url, logLevel);
178 log("\tall:" + all, logLevel);
179 log("\ttypeMappingVersion:" + typeMappingVersion, logLevel);
180 log("\ttimeout:" + timeout, logLevel);
181 log("\tfailOnNetworkErrors:" + failOnNetworkErrors, logLevel);
182 log("\tprintStackTraceOnFailure:" + printStackTraceOnFailure, logLevel);
183 log("\tnamespaceMappingFile:" + namespaceMappingFile, logLevel);
184 log("\tusername:" + username, logLevel);
185 log("\t:password" + password, logLevel);
186 log("\t:noWrapped" + noWrapped, logLevel);
187 log("\t:allowInvalidURL" + allowInvalidURL, logLevel);
188 log("\t:implementationClassName" + implementationClassName, logLevel);
189 log("\t:classpath" + classpath, logLevel);
190 traceNetworkSettings(logLevel);
191 }
192
193 /**
194 * The method executing the task
195 * @throws BuildException if validation or execution failed
196 */
197 public void execute() throws BuildException {
198 //before we get any further, if the user didnt spec a namespace mapping
199 //file, we load in the default
200
201 traceParams(Project.MSG_VERBOSE);
202 validate();
203 CommandlineJava.SysProperties sysProperties =
204 commandline.getSystemProperties();
205 if (sysProperties != null) {
206 sysProperties.setSystem();
207 }
208
209 try {
210 // Instantiate the emitter
211 Emitter emitter = createEmitter();
212
213 //extract the scope
214 Scope scope = Scope.getScope(deployScope, null);
215 if (scope != null) {
216 emitter.setScope(scope);
217 } else if (deployScope.length() == 0
218 || "none".equalsIgnoreCase(deployScope)) {
219 /* leave default (null, or not-explicit) */;
220 } else {
221 log("Unrecognized scope: " + deployScope + ". Ignoring it.", Project.MSG_VERBOSE);
222 }
223
224 //do the mappings, with namespaces mapped as the key
225 mappings.execute(this, namespaceMap, false);
226 if (!namespaceMap.isEmpty()) {
227 emitter.setNamespaceMap(namespaceMap);
228 }
229 emitter.setTestCaseWanted(testCase);
230 emitter.setHelperWanted(helperGen);
231 if (factory != null) {
232 emitter.setFactory(factory);
233 }
234 emitter.setNamespaceIncludes(nsIncludes);
235 emitter.setNamespaceExcludes(nsExcludes);
236 emitter.setProperties(properties);
237 emitter.setImports(!noImports);
238 emitter.setAllWanted(all);
239 emitter.setOutputDir(output);
240 emitter.setServerSide(server);
241 emitter.setSkeletonWanted(skeletonDeploy);
242 emitter.setVerbose(verbose);
243 emitter.setDebug(debug);
244 emitter.setQuiet(quiet);
245 emitter.setTypeMappingVersion(typeMappingVersion);
246 emitter.setNowrap(noWrapped);
247 emitter.setAllowInvalidURL(allowInvalidURL);
248 emitter.setWrapArrays(wrapArrays);
249 if (namespaceMappingFile != null) {
250 emitter.setNStoPkg(namespaceMappingFile.toString());
251 }
252 emitter.setTimeout(timeout);
253 emitter.setImplementationClassName(implementationClassName);
254
255 Authenticator.setDefault(new DefaultAuthenticator(username, password));
256 if (classpath != null) {
257 AntClassLoader cl = new AntClassLoader(
258 getClass().getClassLoader(),
259 getProject(),
260 classpath,
261 false);
262 log("Using CLASSPATH " + cl.getClasspath(),
263 Project.MSG_VERBOSE);
264 ClassUtils.setDefaultClassLoader(cl);
265 }
266
267 try {
268 if(url.indexOf(':') == -1)
269 url = getProject().resolveFile(url).getAbsolutePath();
270 } catch (Throwable t){
271 }
272
273 log("WSDL2Java " + url, Project.MSG_INFO);
274 try {
275 emitter.run(url);
276 } catch (Throwable e) {
277 if (url.startsWith("http://")) {
278 // What we have is either a network error or invalid XML -
279 // the latter most likely an HTML error page. This makes
280 // it impossible to continue with the test, so we stop here
281 if (!failOnNetworkErrors) {
282 // test mode, issue a warning, and return without
283 //reporting a fatal error.
284 log(e.toString(), Project.MSG_WARN);
285 return;
286 } else {
287 //in 'consumer' mode, bail out with the URL
288 throw new BuildException("Could not build " + url, e);
289 }
290 } else {
291 throw e;
292 }
293 }
294 } catch (BuildException b) {
295 //we rethrow this immediately; but need to catch it to stop it being
296 //mistaken for a throwable.
297 throw b;
298 } catch (Throwable t) {
299 if (printStackTraceOnFailure) {
300 traceParams(Project.MSG_INFO);
301 t.printStackTrace();
302 }
303 //now throw an exception that includes the error text of the caught exception.
304 throw new BuildException("WSDL processing error for "
305 + url +" :\n "+t.getMessage() , t);
306 } finally {
307 if (sysProperties != null) {
308 sysProperties.restoreSystem();
309 }
310 }
311
312 }
313
314 /**
315 * flag for verbose output; default=false
316 *
317 *@param verbose The new verbose value
318 */
319 public void setVerbose(boolean verbose) {
320 this.verbose = verbose;
321 }
322
323 /**
324 * flag for debug output; default=false
325 *
326 *@param debug The new debug value
327 */
328 public void setDebug(boolean debug) {
329 this.debug = debug;
330 }
331
332 /**
333 * flag for quiet output; default=false
334 *
335 *@param quiet The new quiet value
336 */
337 public void setQuiet(boolean quiet) {
338 this.quiet = quiet;
339 }
340
341 /**
342 * emit server-side bindings for web service; default=false
343 */
344 public void setServerSide(boolean parameter) {
345 this.server = parameter;
346 }
347
348 /**
349 * deploy skeleton (true) or implementation (false) in deploy.wsdd.
350 * Default is false. Assumes server-side="true".
351 */
352 public void setSkeletonDeploy(boolean parameter) {
353 this.skeletonDeploy = parameter;
354 }
355
356 /**
357 * flag for automatic Junit testcase generation
358 * default is false
359 */
360 public void setTestCase(boolean parameter) {
361 this.testCase = parameter;
362 }
363
364 /**
365 * Turn on/off Helper class generation;
366 * default is false
367 */
368 public void setHelperGen(boolean parameter) {
369 this.helperGen = parameter;
370 }
371
372 /**
373 * name of the Java2WSDLFactory class for
374 * extending WSDL generation functions
375 */
376 public void setFactory(String parameter) {
377 this.factory = parameter;
378 }
379
380 /**
381 * only generate code for the immediate WSDL document,
382 * and not imports; default=false;
383 */
384 public void setNoImports(boolean parameter) {
385 this.noImports = parameter;
386 }
387
388 /**
389 * output directory for emitted files
390 */
391 public void setOutput(File parameter) throws BuildException {
392 try {
393 this.output = parameter.getCanonicalPath();
394 } catch (IOException ioe) {
395 throw new BuildException(ioe);
396 }
397 }
398
399 /**
400 * append any protocol handler pkgs specified with the task
401 */
402 public void setProtocolHandlerPkgs(String handlerPkgs) {
403 String currentPkgs = System.getProperty("java.protocol.handler.pkgs");
404 String newPkgs = null;
405
406 if (currentPkgs == null)
407 newPkgs = handlerPkgs;
408 else
409 // append to the existing list
410 newPkgs = currentPkgs + "|" + handlerPkgs;
411
412 System.setProperty("java.protocol.handler.pkgs", newPkgs);
413 }
414
415 /**
416 * add scope to deploy.xml: "Application", "Request", "Session"
417 * optional;
418 */
419 public void setDeployScope(String scope) {
420 this.deployScope = scope;
421 }
422 /*
423 //unused till we can somehow get ant to be case insensitive when handling enums
424 public void setDeployScope(DeployScopeEnum scope) {
425 this.deployScope = scope.getValue();
426 }
427 */
428 /**
429 * URL to fetch and generate WSDL for.
430 * Can be remote or a local file.
431 */
432 public void setURL(String parameter) {
433 this.url = parameter;
434 }
435
436 /**
437 * flag to generate code for all elements, even unreferenced ones
438 * default=false;
439 */
440 public void setAll(boolean parameter) {
441 this.all = parameter;
442 }
443
444 /**
445 * the default type mapping registry to use. Either 1.1 or 1.2.
446 * Default is 1.1
447 * @param parameter new version
448 */
449 public void setTypeMappingVersion(TypeMappingVersionEnum parameter) {
450 this.typeMappingVersion = parameter.getValue();
451 }
452
453 /**
454 * timeout in milliseconds for URL retrieval; default is 45 seconds.
455 * Set this to -1 to disable timeouts altogether: other negative values
456 * are not allowed)
457 */
458 public void setTimeout(long parameter) {
459 this.timeout = parameter;
460 }
461
462 /**
463 * add a mapping of namespaces to packages
464 */
465 public void addMapping(NamespaceMapping mapping) {
466 mappings.addMapping(mapping);
467 }
468
469 /**
470 * add a mapping of namespaces to packages
471 */
472 public void addMappingSet(MappingSet mappingset) {
473 mappings.addMappingSet(mappingset);
474 }
475
476 /**
477 * set the mapping file. This is a properties file of
478 * package=namespace order. Optional, default is to look for
479 * a file called NStoPkg.properties in the project directory.
480 * @param namespaceMappingFile
481 */
482 public void setNamespaceMappingFile(File namespaceMappingFile) {
483 this.namespaceMappingFile = namespaceMappingFile;
484 }
485
486 /**
487 * valid deploy scopes for the task
488 */
489 /*
490 public static class DeployScopeEnum extends EnumeratedAttribute {
491 public String[] getValues() {
492 return new String[]{"Application", "Request", "Session","none"};
493 }
494
495 }
496 */
497
498 /**
499 * should the task fail the build if there is a network error?
500 * optional: defaults to false
501 * @param failOnNetworkErrors
502 */
503 public void setFailOnNetworkErrors(boolean failOnNetworkErrors) {
504 this.failOnNetworkErrors = failOnNetworkErrors;
505 }
506
507 /**
508 * should we print a stack trace on failure?
509 * Optional, default=true.
510 * @param printStackTraceOnFailure
511 */
512 public void setPrintStackTraceOnFailure(boolean printStackTraceOnFailure) {
513 this.printStackTraceOnFailure = printStackTraceOnFailure;
514 }
515
516 /**
517 * set any username required for BASIC authenticated access to the WSDL;
518 * optional.
519 * @param username
520 */
521 public void setUsername(String username) {
522 this.username = username;
523 }
524
525 /**
526 * set any password required for BASIC authenticated access to the WSDL;
527 * optional; only used if username is set
528 * @param password
529 * @see #username
530 */
531 public void setPassword(String password) {
532 this.password = password;
533 }
534
535 /**
536 * Set the noWrapped flag.
537 * @param noWrapped
538 */
539 public void setNoWrapped(boolean noWrapped) {
540 this.noWrapped = noWrapped;
541 }
542
543 /**
544 * Set the allowInvalidURL flag.
545 */
546 public void setAllowInvalidUrl(boolean b) {
547 this.allowInvalidURL = b;
548 }
549
550 /**
551 * Set the name of the class implementing the web service.
552 * This is especially useful when exporting a java class
553 * as a web service using Java2WSDL followed by WSDL2Java.
554 *
555 * @param implementationClassName
556 */
557 public void setImplementationClassName(String implementationClassName) {
558 this.implementationClassName = implementationClassName;
559 }
560
561
562 /**
563 * Set the wrap arrays flag - if true this will make new classes
564 * like "ArrayOfString" for literal "wrapped" arrays. Otherwise it
565 * will use "String []" and generate appropriate metadata.
566 *
567 * @param wrapArrays
568 */
569 public void setWrapArrays(boolean wrapArrays) {
570 this.wrapArrays = wrapArrays;
571 }
572
573 /**
574 * set the classpath
575 * @return
576 */
577 public Path createClasspath() {
578 if (classpath == null) {
579 classpath = new Path(getProject());
580 }
581 return classpath.createPath();
582 }
583
584 /** Adds an additional namespace to the list to be included
585 * in source code generation.
586 */
587 public NamespaceSelector createNsInclude() {
588 NamespaceSelector selector = new NamespaceSelector();
589 nsIncludes.add(selector);
590 return selector;
591 }
592
593 /** Adds an additional namespace to the list to be excluded
594 * from source code generation.
595 */
596 public NamespaceSelector createNsExclude() {
597 NamespaceSelector selector = new NamespaceSelector();
598 nsExcludes.add(selector);
599 return selector;
600 }
601
602 /** Adds a property name/value pair for specialized
603 * JavaGeneratorFactories.
604 */
605 public FactoryProperty createProperty() {
606 FactoryProperty property = new FactoryProperty();
607 properties.add(property);
608 return property;
609 }
610
611 /** This factory method makes it easier to extend this Ant task
612 * with a custom Emitter, if necessary.
613 */
614 protected Emitter createEmitter() {
615 return new Emitter();
616 }
617
618 protected NamespaceSelector createSelector() {
619 return new NamespaceSelector();
620 }
621
622 private void traceSystemSetting(String setting, int logLevel) {
623 String value = System.getProperty(setting);
624 log("\t" + setting + "=" + value, logLevel);
625 }
626
627 private void traceNetworkSettings(int logLevel) {
628 traceSystemSetting("http.proxyHost", logLevel);
629 traceSystemSetting("http.proxyPort", logLevel);
630 traceSystemSetting("http.proxyUser", logLevel);
631 traceSystemSetting("http.proxyPassword", logLevel);
632 traceSystemSetting("socks.proxyHost", logLevel);
633 traceSystemSetting("socks.proxyPort", logLevel);
634 }
635
636 /**
637 * Adds a system property that tests can access.
638 * @param sysp environment variable to add
639 */
640 public void addSysproperty(Environment.Variable sysp) {
641 commandline.addSysproperty(sysp);
642 }
643 }
644