Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.internal.xjc;
28 import java.io.File;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.io.OutputStreamWriter;
33 import java.io.PrintStream;
34 import java.util.Iterator;
36 import com.sun.codemodel.internal.CodeWriter;
37 import com.sun.codemodel.internal.JCodeModel;
38 import com.sun.codemodel.internal.writer.ZipCodeWriter;
39 import com.sun.istack.internal.NotNull;
40 import com.sun.istack.internal.Nullable;
41 import com.sun.istack.internal.tools.DefaultAuthenticator;
42 import com.sun.tools.internal.xjc.generator.bean.BeanGenerator;
43 import com.sun.tools.internal.xjc.model.Model;
44 import com.sun.tools.internal.xjc.outline.Outline;
45 import com.sun.tools.internal.xjc.reader.gbind.Expression;
46 import com.sun.tools.internal.xjc.reader.gbind.Graph;
47 import com.sun.tools.internal.xjc.reader.internalizer.DOMForest;
48 import com.sun.tools.internal.xjc.reader.xmlschema.ExpressionBuilder;
49 import com.sun.tools.internal.xjc.reader.xmlschema.parser.XMLSchemaInternalizationLogic;
50 import com.sun.tools.internal.xjc.util.ErrorReceiverFilter;
51 import com.sun.tools.internal.xjc.util.NullStream;
52 import com.sun.tools.internal.xjc.util.Util;
53 import com.sun.tools.internal.xjc.writer.SignatureWriter;
54 import com.sun.xml.internal.xsom.XSComplexType;
55 import com.sun.xml.internal.xsom.XSParticle;
56 import com.sun.xml.internal.xsom.XSSchemaSet;
58 import org.xml.sax.SAXException;
59 import org.xml.sax.SAXParseException;
62 /**
63 * Command Line Interface of XJC.
64 */
65 public class Driver {
67 public static void main(final String[] args) throws Exception {
68 // use the platform default proxy if available.
69 // see sun.net.spi.DefaultProxySelector for details.
70 try {
71 System.setProperty("java.net.useSystemProxies","true");
72 } catch (SecurityException e) {
73 // failing to set this property isn't fatal
74 }
76 if( Util.getSystemProperty(Driver.class,"noThreadSwap")!=null )
77 _main(args); // for the ease of debugging
79 // run all the work in another thread so that the -Xss option
80 // will take effect when compiling a large schema. See
81 // http://developer.java.sun.com/developer/bugParade/bugs/4362291.html
82 final Throwable[] ex = new Throwable[1];
84 Thread th = new Thread() {
85 @Override
86 public void run() {
87 try {
88 _main(args);
89 } catch( Throwable e ) {
90 ex[0]=e;
91 }
92 }
93 };
94 th.start();
95 th.join();
97 if(ex[0]!=null) {
98 // re-throw
99 if( ex[0] instanceof Exception )
100 throw (Exception)ex[0];
101 else
102 throw (Error)ex[0];
103 }
104 }
106 private static void _main( String[] args ) throws Exception {
107 try {
108 System.exit(run( args, System.out, System.out ));
109 } catch (BadCommandLineException e) {
110 // there was an error in the command line.
111 // print usage and abort.
112 if(e.getMessage()!=null) {
113 System.out.println(e.getMessage());
114 System.out.println();
115 }
117 usage(e.getOptions(),false);
118 System.exit(-1);
119 }
120 }
124 /**
125 * Performs schema compilation and prints the status/error into the
126 * specified PrintStream.
127 *
128 * <p>
129 * This method could be used to trigger XJC from other tools,
130 * such as Ant or IDE.
131 *
132 * @param args
133 * specified command line parameters. If there is an error
134 * in the parameters, {@link BadCommandLineException} will
135 * be thrown.
136 * @param status
137 * Status report of the compilation will be sent to this object.
138 * Useful to update users so that they will know something is happening.
139 * Only ignorable messages should be sent to this stream.
140 *
141 * This parameter can be null to suppress messages.
142 *
143 * @param out
144 * Various non-ignorable output (error messages, etc)
145 * will go to this stream.
146 *
147 * @return
148 * If the compiler runs successfully, this method returns 0.
149 * All non-zero values indicate an error. The error message
150 * will be sent to the specified PrintStream.
151 */
152 public static int run(String[] args, final PrintStream status, final PrintStream out)
153 throws Exception {
155 class Listener extends XJCListener {
156 ConsoleErrorReporter cer = new ConsoleErrorReporter(out==null?new PrintStream(new NullStream()):out);
158 @Override
159 public void generatedFile(String fileName, int count, int total) {
160 message(fileName);
161 }
162 @Override
163 public void message(String msg) {
164 if(status!=null)
165 status.println(msg);
166 }
168 public void error(SAXParseException exception) {
169 cer.error(exception);
170 }
172 public void fatalError(SAXParseException exception) {
173 cer.fatalError(exception);
174 }
176 public void warning(SAXParseException exception) {
177 cer.warning(exception);
178 }
180 public void info(SAXParseException exception) {
181 cer.info(exception);
182 }
183 }
185 return run(args,new Listener());
186 }
188 /**
189 * Performs schema compilation and prints the status/error into the
190 * specified PrintStream.
191 *
192 * <p>
193 * This method could be used to trigger XJC from other tools,
194 * such as Ant or IDE.
195 *
196 * @param args
197 * specified command line parameters. If there is an error
198 * in the parameters, {@link BadCommandLineException} will
199 * be thrown.
200 * @param listener
201 * Receives messages from XJC reporting progress/errors.
202 *
203 * @return
204 * If the compiler runs successfully, this method returns 0.
205 * All non-zero values indicate an error. The error message
206 * will be sent to the specified PrintStream.
207 */
208 public static int run(String[] args, @NotNull final XJCListener listener) throws BadCommandLineException {
210 // recognize those special options before we start parsing options.
211 for (String arg : args) {
212 if (arg.equals("-version")) {
213 listener.message(Messages.format(Messages.VERSION));
214 return -1;
215 }
216 if (arg.equals("-fullversion")) {
217 listener.message(Messages.format(Messages.FULLVERSION));
218 return -1;
219 }
220 }
222 final OptionsEx opt = new OptionsEx();
223 opt.setSchemaLanguage(Language.XMLSCHEMA); // disable auto-guessing
224 try {
225 opt.parseArguments(args);
226 } catch (WeAreDone e) {
227 if (opt.proxyAuth != null) {
228 DefaultAuthenticator.reset();
229 }
230 return -1;
231 } catch(BadCommandLineException e) {
232 if (opt.proxyAuth != null) {
233 DefaultAuthenticator.reset();
234 }
235 e.initOptions(opt);
236 throw e;
237 }
239 // display a warning if the user specified the default package
240 // this should work, but is generally a bad idea
241 if(opt.defaultPackage != null && opt.defaultPackage.length()==0) {
242 listener.message(Messages.format(Messages.WARNING_MSG, Messages.format(Messages.DEFAULT_PACKAGE_WARNING)));
243 }
246 // set up the context class loader so that the user-specified classes
247 // can be loaded from there
248 final ClassLoader contextClassLoader = SecureLoader.getContextClassLoader();
249 SecureLoader.setContextClassLoader(opt.getUserClassLoader(contextClassLoader));
251 // parse a grammar file
252 //-----------------------------------------
253 try {
254 if( !opt.quiet ) {
255 listener.message(Messages.format(Messages.PARSING_SCHEMA));
256 }
258 final boolean[] hadWarning = new boolean[1];
260 ErrorReceiver receiver = new ErrorReceiverFilter(listener) {
261 @Override
262 public void info(SAXParseException exception) {
263 if(opt.verbose)
264 super.info(exception);
265 }
266 @Override
267 public void warning(SAXParseException exception) {
268 hadWarning[0] = true;
269 if(!opt.quiet)
270 super.warning(exception);
271 }
272 @Override
273 public void pollAbort() throws AbortException {
274 if(listener.isCanceled())
275 throw new AbortException();
276 }
277 };
279 if( opt.mode==Mode.FOREST ) {
280 // dump DOM forest and quit
281 ModelLoader loader = new ModelLoader( opt, new JCodeModel(), receiver );
282 try {
283 DOMForest forest = loader.buildDOMForest(new XMLSchemaInternalizationLogic());
284 forest.dump(System.out);
285 return 0;
286 } catch (SAXException e) {
287 // the error should have already been reported
288 } catch (IOException e) {
289 receiver.error(e);
290 }
292 return -1;
293 }
295 if( opt.mode==Mode.GBIND ) {
296 try {
297 XSSchemaSet xss = new ModelLoader(opt, new JCodeModel(), receiver).loadXMLSchema();
298 Iterator<XSComplexType> it = xss.iterateComplexTypes();
299 while (it.hasNext()) {
300 XSComplexType ct = it.next();
301 XSParticle p = ct.getContentType().asParticle();
302 if(p==null) continue;
304 Expression tree = ExpressionBuilder.createTree(p);
305 System.out.println("Graph for "+ct.getName());
306 System.out.println(tree.toString());
307 Graph g = new Graph(tree);
308 System.out.println(g.toString());
309 System.out.println();
310 }
311 return 0;
312 } catch (SAXException e) {
313 // the error should have already been reported
314 }
315 return -1;
316 }
318 Model model = ModelLoader.load( opt, new JCodeModel(), receiver );
320 if (model == null) {
321 listener.message(Messages.format(Messages.PARSE_FAILED));
322 return -1;
323 }
325 if( !opt.quiet ) {
326 listener.message(Messages.format(Messages.COMPILING_SCHEMA));
327 }
329 switch (opt.mode) {
330 case SIGNATURE :
331 try {
332 SignatureWriter.write(
333 BeanGenerator.generate(model,receiver),
334 new OutputStreamWriter(System.out));
335 return 0;
336 } catch (IOException e) {
337 receiver.error(e);
338 return -1;
339 }
341 case CODE :
342 case DRYRUN :
343 case ZIP :
344 {
345 // generate actual code
346 receiver.debug("generating code");
347 {// don't want to hold outline in memory for too long.
348 Outline outline = model.generateCode(opt,receiver);
349 if(outline==null) {
350 listener.message(
351 Messages.format(Messages.FAILED_TO_GENERATE_CODE));
352 return -1;
353 }
355 listener.compiled(outline);
356 }
358 if( opt.mode == Mode.DRYRUN )
359 break; // enough
361 // then print them out
362 try {
363 CodeWriter cw;
364 if( opt.mode==Mode.ZIP ) {
365 OutputStream os;
366 if(opt.targetDir.getPath().equals("."))
367 os = System.out;
368 else
369 os = new FileOutputStream(opt.targetDir);
371 cw = opt.createCodeWriter(new ZipCodeWriter(os));
372 } else
373 cw = opt.createCodeWriter();
375 if( !opt.quiet ) {
376 cw = new ProgressCodeWriter(cw,listener, model.codeModel.countArtifacts());
377 }
378 model.codeModel.build(cw);
379 } catch (IOException e) {
380 receiver.error(e);
381 return -1;
382 }
384 break;
385 }
386 default :
387 assert false;
388 }
390 if(opt.debugMode) {
391 try {
392 new FileOutputStream(new File(opt.targetDir,hadWarning[0]?"hadWarning":"noWarning")).close();
393 } catch (IOException e) {
394 receiver.error(e);
395 return -1;
396 }
397 }
399 return 0;
400 } catch( StackOverflowError e ) {
401 if(opt.verbose)
402 // in the debug mode, propagate the error so that
403 // the full stack trace will be dumped to the screen.
404 throw e;
405 else {
406 // otherwise just print a suggested workaround and
407 // quit without filling the user's screen
408 listener.message(Messages.format(Messages.STACK_OVERFLOW));
409 return -1;
410 }
411 } finally {
412 if (opt.proxyAuth != null) {
413 DefaultAuthenticator.reset();
414 }
415 }
416 }
418 public static String getBuildID() {
419 return Messages.format(Messages.BUILD_ID);
420 }
423 /**
424 * Operation mode.
425 */
426 private static enum Mode {
427 // normal mode. compile the code
428 CODE,
430 // dump the signature of the generated code
431 SIGNATURE,
433 // dump DOMForest
434 FOREST,
436 // same as CODE but don't produce any Java source code
437 DRYRUN,
439 // same as CODE but pack all the outputs into a zip and dumps to stdout
440 ZIP,
442 // testing a new binding mode
443 GBIND
444 }
447 /**
448 * Command-line arguments processor.
449 *
450 * <p>
451 * This class contains options that only make sense
452 * for the command line interface.
453 */
454 static class OptionsEx extends Options
455 {
456 /** Operation mode. */
457 protected Mode mode = Mode.CODE;
459 /** A switch that determines the behavior in the BGM mode. */
460 public boolean noNS = false;
462 /** Parse XJC-specific options. */
463 @Override
464 public int parseArgument(String[] args, int i) throws BadCommandLineException {
465 if (args[i].equals("-noNS")) {
466 noNS = true;
467 return 1;
468 }
469 if (args[i].equals("-mode")) {
470 i++;
471 if (i == args.length)
472 throw new BadCommandLineException(
473 Messages.format(Messages.MISSING_MODE_OPERAND));
475 String mstr = args[i].toLowerCase();
477 for( Mode m : Mode.values() ) {
478 if(m.name().toLowerCase().startsWith(mstr) && mstr.length()>2) {
479 mode = m;
480 return 2;
481 }
482 }
484 throw new BadCommandLineException(
485 Messages.format(Messages.UNRECOGNIZED_MODE, args[i]));
486 }
487 if (args[i].equals("-help")) {
488 usage(this,false);
489 throw new WeAreDone();
490 }
491 if (args[i].equals("-private")) {
492 usage(this,true);
493 throw new WeAreDone();
494 }
496 return super.parseArgument(args, i);
497 }
498 }
500 /**
501 * Used to signal that we've finished processing.
502 */
503 private static final class WeAreDone extends BadCommandLineException {}
506 /**
507 * Prints the usage screen and exits the process.
508 *
509 * @param opts
510 * If the parsing of options have started, set a partly populated
511 * {@link Options} object.
512 */
513 public static void usage( @Nullable Options opts, boolean privateUsage ) {
514 System.out.println(Messages.format(Messages.DRIVER_PUBLIC_USAGE));
515 if (privateUsage) {
516 System.out.println(Messages.format(Messages.DRIVER_PRIVATE_USAGE));
517 }
519 if( opts!=null && !opts.getAllPlugins().isEmpty()) {
520 System.out.println(Messages.format(Messages.ADDON_USAGE));
521 for (Plugin p : opts.getAllPlugins()) {
522 System.out.println(p.getUsage());
523 }
524 }
525 }
526 }