< prev index next >

src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/Options.java

Print this page




  60 import com.sun.xml.internal.bind.api.impl.NameConverter;
  61 import java.net.URI;
  62 import java.net.URISyntaxException;
  63 import java.nio.charset.Charset;
  64 import java.nio.charset.IllegalCharsetNameException;
  65 import java.util.Locale;
  66 import java.util.logging.Level;
  67 import java.util.logging.Logger;
  68 
  69 import org.xml.sax.EntityResolver;
  70 import org.xml.sax.InputSource;
  71 
  72 /**
  73  * Global options.
  74  *
  75  * <p>
  76  * This class stores invocation configuration for XJC.
  77  * The configuration in this class should be abstract enough so that
  78  * it could be parsed from both command-line or Ant.
  79  */
  80 public class Options
  81 {
  82     /** If "-debug" is specified. */

  83     public boolean debugMode;
  84 
  85     /** If the "-verbose" option is specified. */


  86     public boolean verbose;
  87 
  88     /** If the "-quiet" option is specified. */


  89     public boolean quiet;
  90 
  91     /** If the -readOnly option is specified. */


  92     public boolean readOnly;
  93 
  94     /** No file header comment (to be more friendly with diff.) */


  95     public boolean noFileHeader;
  96 
  97     /** When on, fixes getter/setter generation to match the Bean Introspection API */


  98     public boolean enableIntrospection;
  99 
 100     /** When on, generates content property for types with multiple xs:any derived elements (which is supposed to be correct behaviour) */


 101     public boolean contentForWildcard;
 102 
 103     /** Encoding to be used by generated java sources, null for platform default. */


 104     public String encoding;
 105 
 106     /**
 107      * If true XML security features when parsing XML documents will be disabled.
 108      * The default value is false.
 109      *
 110      * Boolean

 111      * @since 2.2.6
 112      */
 113     public boolean disableXmlSecurity;
 114 
 115     /**
 116      * Check the source schemas with extra scrutiny.
 117      * The exact meaning depends on the schema language.
 118      */
 119     public boolean strictCheck =true;
 120 
 121     /**
 122      * If -explicit-annotation option is specified.
 123      * <p>
 124      * This generates code that works around issues specific to 1.4 runtime.
 125      */
 126     public boolean runtime14 = false;
 127 
 128     /**
 129      * If true, try to resolve name conflicts automatically by assigning mechanical numbers.
 130      */
 131     public boolean automaticNameConflictResolution = false;
 132 
 133     /**
 134      * strictly follow the compatibility rules and reject schemas that
 135      * contain features from App. E.2, use vendor binding extensions
 136      */
 137     public static final int STRICT = 1;
 138     /**
 139      * loosely follow the compatibility rules and allow the use of vendor
 140      * binding extensions
 141      */
 142     public static final int EXTENSION = 2;
 143 
 144     /**
 145      * this switch determines how carefully the compiler will follow
 146      * the compatibility rules in the spec. Either {@code STRICT}
 147      * or {@code EXTENSION}.
 148      */
 149     public int compatibilityMode = STRICT;
 150 
 151     public boolean isExtensionMode() {
 152         return compatibilityMode==EXTENSION;
 153     }
 154 
 155     private static final Logger logger = com.sun.xml.internal.bind.Util.getClassLogger();
 156 
 157     /**
 158      * Generates output for the specified version of the runtime.
 159      */
 160     public SpecVersion target = SpecVersion.LATEST;
 161 
 162 
 163     public Options() {
 164         try {
 165             Class.forName("javax.xml.bind.JAXBPermission");
 166         } catch (ClassNotFoundException cnfe) {
 167             target = SpecVersion.V2_1;
 168         }
 169     }
 170 
 171     /**
 172      * Target directory when producing files.


 260      * Used to detect if two {@link Plugin}s try to overwrite {@link #nameConverter}.
 261      */
 262     private Plugin nameConverterOwner = null;
 263 
 264     /**
 265      * Java module name in {@code module-info.java}.
 266      */
 267     private String javaModule = null;
 268 
 269     /**
 270      * Gets the active {@link FieldRendererFactory} that shall be used to build {@link Model}.
 271      *
 272      * @return always non-null.
 273      */
 274     public FieldRendererFactory getFieldRendererFactory() {
 275         return fieldRendererFactory;
 276     }
 277 
 278     /**
 279      * Sets the {@link FieldRendererFactory}.
 280      *
 281      * <p>
 282      * This method is for plugins to call to set a custom {@link FieldRendererFactory}.
 283      *
 284      * @param frf
 285      *      The {@link FieldRendererFactory} to be installed. Must not be null.
 286      * @param owner
 287      *      Identifies the plugin that owns this {@link FieldRendererFactory}.
 288      *      When two {@link Plugin}s try to call this method, this allows XJC
 289      *      to report it as a user-friendly error message.
 290      *
 291      * @throws BadCommandLineException
 292      *      If a conflit happens, this exception carries a user-friendly error
 293      *      message, indicating a conflict.
 294      */
 295     public void setFieldRendererFactory(FieldRendererFactory frf, Plugin owner) throws BadCommandLineException {
 296         // since this method is for plugins, make it bit more fool-proof than usual
 297         if(frf==null)
 298             throw new IllegalArgumentException();
 299         if(fieldRendererFactoryOwner!=null) {
 300             throw new BadCommandLineException(
 301                 Messages.format(Messages.FIELD_RENDERER_CONFLICT,
 302                     fieldRendererFactoryOwner.getOptionName(),
 303                     owner.getOptionName() ));
 304         }
 305         this.fieldRendererFactoryOwner = owner;
 306         this.fieldRendererFactory = frf;
 307     }
 308 
 309 
 310     /**
 311      * Gets the active {@link NameConverter} that shall be used to build {@link Model}.
 312      *
 313      * @return can be null, in which case it's up to the binding.
 314      */
 315     public NameConverter getNameConverter() {
 316         return nameConverter;
 317     }
 318 
 319     /**
 320      * Sets the {@link NameConverter}.
 321      *
 322      * <p>
 323      * This method is for plugins to call to set a custom {@link NameConverter}.
 324      *
 325      * @param nc
 326      *      The {@link NameConverter} to be installed. Must not be null.
 327      * @param owner
 328      *      Identifies the plugin that owns this {@link NameConverter}.
 329      *      When two {@link Plugin}s try to call this method, this allows XJC
 330      *      to report it as a user-friendly error message.
 331      *
 332      * @throws BadCommandLineException
 333      *      If a conflit happens, this exception carries a user-friendly error
 334      *      message, indicating a conflict.
 335      */
 336     public void setNameConverter(NameConverter nc, Plugin owner) throws BadCommandLineException {
 337         // since this method is for plugins, make it bit more fool-proof than usual
 338         if(nc==null)
 339             throw new IllegalArgumentException();
 340         if(nameConverter!=null) {
 341             throw new BadCommandLineException(
 342                 Messages.format(Messages.NAME_CONVERTER_CONFLICT,
 343                     nameConverterOwner.getOptionName(),
 344                     owner.getOptionName() ));
 345         }
 346         this.nameConverterOwner = owner;
 347         this.nameConverter = nc;
 348     }
 349 
 350     /**
 351      * Gets all the {@link Plugin}s discovered so far.
 352      *
 353      * <p>
 354      * A plugins are enumerated when this method is called for the first time,
 355      * by taking {@link #classpaths} into account. That means
 356      * "-cp plugin.jar" has to come before you specify options to enable it.

 357      * @return
 358      */
 359     public List<Plugin> getAllPlugins() {
 360         if(allPlugins==null) {
 361             allPlugins = findServices(Plugin.class);
 362         }
 363 
 364         return allPlugins;
 365     }
 366 
 367     public Language getSchemaLanguage() {
 368         if( schemaLanguage==null)
 369             schemaLanguage = guessSchemaLanguage();
 370         return schemaLanguage;
 371     }

 372     public void setSchemaLanguage(Language _schemaLanguage) {
 373         this.schemaLanguage = _schemaLanguage;
 374     }
 375 
 376     /** Input schema files.
 377      * @return  */



 378     public InputSource[] getGrammars() {
 379         return grammars.toArray(new InputSource[grammars.size()]);
 380     }
 381 
 382     /**
 383      * Adds a new input schema.

 384      * @param is
 385      */
 386     public void addGrammar( InputSource is ) {
 387         grammars.add(absolutize(is));
 388     }
 389 
 390     private InputSource fileToInputSource( File source ) {
 391         try {
 392             String url = source.toURL().toExternalForm();
 393             return new InputSource(Util.escapeSpace(url));
 394         } catch (MalformedURLException e) {
 395             return new InputSource(source.getPath());
 396         }
 397     }
 398 
 399     public void addGrammar( File source ) {
 400         addGrammar(fileToInputSource(source));
 401     }
 402 
 403     /**
 404      * Recursively scan directories and add all XSD files in it.

 405      * @param dir
 406      */
 407     public void addGrammarRecursive( File dir ) {
 408         addRecursive(dir,".xsd",grammars);
 409     }
 410 
 411     private  void addRecursive( File dir, String suffix, List<InputSource> result ) {
 412         File[] files = dir.listFiles();
 413         if(files==null)     return; // work defensively
 414 
 415         for( File f : files ) {
 416             if(f.isDirectory())
 417                 addRecursive(f,suffix,result);
 418             else
 419             if(f.getPath().endsWith(suffix))
 420                 result.add(absolutize(fileToInputSource(f)));
 421         }
 422     }
 423 
 424 
 425     private InputSource absolutize(InputSource is) {
 426         // absolutize all the system IDs in the input, so that we can map system IDs to DOM trees.
 427         try {
 428             URL baseURL = new File(".").getCanonicalFile().toURL();
 429             is.setSystemId( new URL(baseURL,is.getSystemId()).toExternalForm() );
 430         } catch( IOException e ) {
 431             logger.log(Level.FINE, "{0}, {1}", new Object[]{is.getSystemId(), e.getLocalizedMessage()});
 432         }
 433         return is;
 434     }
 435 
 436     /** Input external binding files.
 437      * @return  */



 438     public InputSource[] getBindFiles() {
 439         return bindFiles.toArray(new InputSource[bindFiles.size()]);
 440     }
 441 
 442     /**
 443      * Adds a new binding file.

 444      * @param is
 445      */
 446     public void addBindFile( InputSource is ) {
 447         bindFiles.add(absolutize(is));
 448     }
 449 
 450     /**
 451      * Adds a new binding file.

 452      * @param bindFile
 453      */
 454     public void addBindFile( File bindFile ) {
 455         bindFiles.add(fileToInputSource(bindFile));
 456     }
 457 
 458     /**
 459      * Recursively scan directories and add all ".xjb" files in it.

 460      * @param dir
 461      */
 462     public void addBindFileRecursive( File dir ) {
 463         addRecursive(dir,".xjb",bindFiles);
 464     }
 465 
 466     public final List<URL> classpaths = new ArrayList<>();

 467     /**
 468      * Gets a classLoader that can load classes specified via the
 469      * -classpath option.

 470      * @param parent
 471      * @return
 472      */
 473     public ClassLoader getUserClassLoader( ClassLoader parent ) {
 474         if (classpaths.isEmpty())
 475             return parent;
 476         return new URLClassLoader(
 477                 classpaths.toArray(new URL[classpaths.size()]),parent);
 478     }
 479 
 480     /**
 481      * Gets Java module name option.

 482      * @return Java module name option or {@code null} if this option was not set.
 483      */
 484     public String getModuleName() {
 485         return javaModule;
 486     }
 487 
 488     /**
 489      * Parses an option {@code args[i]} and return
 490      * the number of tokens consumed.
 491      *
 492      * @param args
 493      * @param i
 494      * @return
 495      *      0 if the argument is not understood. Returning 0
 496      *      will let the caller report an error.
 497      * @exception BadCommandLineException
 498      *      If the callee wants to provide a custom message for an error.
 499      */
 500     public int parseArgument( String[] args, int i ) throws BadCommandLineException {
 501         if (args[i].equals("-classpath") || args[i].equals("-cp")) {
 502             String a = requireArgument(args[i], args, ++i);
 503             for (String p : a.split(File.pathSeparator)) {
 504                 File file = new File(p);
 505                 try {
 506                     classpaths.add(file.toURL());
 507                 } catch (MalformedURLException e) {
 508                     throw new BadCommandLineException(
 509                         Messages.format(Messages.NOT_A_VALID_FILENAME,file),e);
 510                 }
 511             }
 512             return 2;
 513         }
 514         if (args[i].equals("-d")) {
 515             targetDir = new File(requireArgument("-d",args,++i));
 516             if( !targetDir.exists() )
 517                 throw new BadCommandLineException(
 518                     Messages.format(Messages.NON_EXISTENT_DIR,targetDir));
 519             return 2;
 520         }
 521         if (args[i].equals("-readOnly")) {
 522             readOnly = true;
 523             return 1;
 524         }
 525         if (args[i].equals("-p")) {
 526             defaultPackage = requireArgument("-p",args,++i);
 527             if(defaultPackage.length()==0) { // user specified default package
 528                 // there won't be any package to annotate, so disable them
 529                 // automatically as a usability feature
 530                 packageLevelAnnotations = false;
 531             }
 532             return 2;
 533         }
 534         if (args[i].equals("-m")) {
 535             javaModule = requireArgument("-m", args, ++i);
 536             return 2;
 537         }
 538         if (args[i].equals("-debug")) {
 539             debugMode = true;
 540             verbose = true;
 541             return 1;
 542         }
 543         if (args[i].equals("-nv")) {
 544             strictCheck = false;
 545             return 1;
 546         }
 547         if( args[i].equals("-npa")) {
 548             packageLevelAnnotations = false;
 549             return 1;
 550         }
 551         if( args[i].equals("-no-header")) {
 552             noFileHeader = true;
 553             return 1;
 554         }
 555         if (args[i].equals("-verbose")) {
 556             verbose = true;
 557             return 1;
 558         }
 559         if (args[i].equals("-quiet")) {
 560             quiet = true;
 561             return 1;
 562         }
 563         if (args[i].equals("-XexplicitAnnotation")) {
 564             runtime14 = true;
 565             return 1;
 566         }
 567         if (args[i].equals("-enableIntrospection")) {
 568             enableIntrospection = true;
 569             return 1;
 570         }
 571         if (args[i].equals("-disableXmlSecurity")) {
 572             disableXmlSecurity = true;
 573             return 1;
 574         }
 575         if (args[i].equals("-contentForWildcard")) {
 576             contentForWildcard = true;
 577             return 1;
 578         }
 579         if (args[i].equals("-XautoNameResolution")) {
 580             automaticNameConflictResolution = true;
 581             return 1;
 582         }
 583         if (args[i].equals("-b")) {
 584             addFile(requireArgument("-b",args,++i),bindFiles,".xjb");
 585             return 2;
 586         }
 587         if (args[i].equals("-dtd")) {
 588             schemaLanguage = Language.DTD;
 589             return 1;
 590         }
 591         if (args[i].equals("-xmlschema")) {
 592             schemaLanguage = Language.XMLSCHEMA;
 593             return 1;
 594         }
 595         if (args[i].equals("-wsdl")) {
 596             schemaLanguage = Language.WSDL;
 597             return 1;
 598         }
 599         if (args[i].equals("-extension")) {
 600             compatibilityMode = EXTENSION;
 601             return 1;
 602         }
 603         if (args[i].equals("-target")) {
 604             String token = requireArgument("-target",args,++i);
 605             target = SpecVersion.parse(token);
 606             if(target==null)
 607                 throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_TARGET_VERSION,token));
 608             return 2;
 609         }
 610         if (args[i].equals("-httpproxyfile")) {
 611             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
 612                 throw new BadCommandLineException(
 613                     Messages.format(Messages.MISSING_PROXYFILE));
 614             }
 615 
 616             File file = new File(args[++i]);
 617             if(!file.exists()) {
 618                 throw new BadCommandLineException(
 619                     Messages.format(Messages.NO_SUCH_FILE,file));
 620             }
 621 
 622             try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"))) {
 623                 parseProxy(in.readLine());
 624             } catch (IOException e) {
 625                 throw new BadCommandLineException(
 626                     Messages.format(Messages.FAILED_TO_PARSE,file,e.getMessage()),e);
 627             }
 628 
 629             return 2;
 630         }
 631         if (args[i].equals("-httpproxy")) {
 632             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
 633                 throw new BadCommandLineException(
 634                     Messages.format(Messages.MISSING_PROXY));
 635             }
 636 
 637             parseProxy(args[++i]);
 638             return 2;
 639         }
 640         if (args[i].equals("-host")) {
 641             proxyHost = requireArgument("-host",args,++i);
 642             return 2;
 643         }
 644         if (args[i].equals("-port")) {
 645             proxyPort = requireArgument("-port",args,++i);
 646             return 2;
 647         }
 648         if( args[i].equals("-catalog") ) {
 649             // use Sun's "XML Entity and URI Resolvers" by Norman Walsh
 650             // to resolve external entities.
 651             // https://xerces.apache.org/xml-commons/components/resolver/resolver-article.html
 652 
 653             File catalogFile = new File(requireArgument("-catalog",args,++i));
 654             try {
 655                 addCatalog(catalogFile);
 656             } catch (IOException e) {
 657                 throw new BadCommandLineException(
 658                     Messages.format(Messages.FAILED_TO_PARSE,catalogFile,e.getMessage()),e);
 659             }
 660             return 2;
 661         }
 662         if( args[i].equals("-Xtest-class-name-allocator") ) {
 663             classNameAllocator = new ClassNameAllocator() {
 664                 @Override
 665                 public String assignClassName(String packageName, String className) {
 666                     System.out.printf("assignClassName(%s,%s)\n",packageName,className);
 667                     return className+"_Type";
 668                 }
 669             };
 670             return 1;
 671         }
 672 
 673         if (args[i].equals("-encoding")) {
 674             encoding = requireArgument("-encoding", args, ++i);
 675             try {
 676                 if (!Charset.isSupported(encoding)) {
 677                     throw new BadCommandLineException(
 678                         Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
 679                 }
 680             } catch (IllegalCharsetNameException icne) {
 681                 throw new BadCommandLineException(
 682                     Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
 683             }
 684             return 2;
 685         }
 686 
 687         // see if this is one of the extensions
 688         for( Plugin plugin : getAllPlugins() ) {
 689             try {
 690                 if( ('-'+plugin.getOptionName()).equals(args[i]) ) {
 691                     activePlugins.add(plugin);
 692                     plugin.onActivated(this);
 693                     pluginURIs.addAll(plugin.getCustomizationURIs());
 694 
 695                     // give the plugin a chance to parse arguments to this option.
 696                     // this is new in 2.1, and due to the backward compatibility reason,
 697                     // if plugin didn't understand it, we still return 1 to indicate
 698                     // that this option is consumed.
 699                     int r = plugin.parseArgument(this,args,i);
 700                     if(r!=0)
 701                         return r;
 702                     else
 703                         return 1;
 704                 }
 705 
 706                 int r = plugin.parseArgument(this,args,i);
 707                 if(r!=0)    return r;
 708             } catch (IOException e) {
 709                 throw new BadCommandLineException(e.getMessage(),e);
 710             }
 711         }
 712 
 713         return 0;   // unrecognized
 714     }
 715 
 716     private void parseProxy(String text) throws BadCommandLineException {
 717         int i = text.lastIndexOf('@');
 718         int j = text.lastIndexOf(':');
 719 
 720         if (i > 0) {
 721             proxyAuth = text.substring(0, i);
 722             if (j > i) {
 723                 proxyHost = text.substring(i + 1, j);
 724                 proxyPort = text.substring(j + 1);
 725             } else {
 726                 proxyHost = text.substring(i + 1);
 727                 proxyPort = "80";
 728             }
 729         } else {
 730             //no auth info
 731             if (j < 0) {
 732                 //no port
 733                 proxyHost = text;
 734                 proxyPort = "80";
 735             } else {
 736                 proxyHost = text.substring(0, j);
 737                 proxyPort = text.substring(j + 1);
 738             }
 739         }
 740         try {
 741             Integer.valueOf(proxyPort);
 742         } catch (NumberFormatException e) {
 743             throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY,text));
 744         }
 745     }
 746 
 747     /**
 748      * Obtains an operand and reports an error if it's not there.

 749      * @param optionName
 750      * @param args
 751      * @param i
 752      * @return
 753      * @throws com.sun.tools.internal.xjc.BadCommandLineException
 754      */
 755     public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException {
 756         if (i == args.length || args[i].startsWith("-")) {
 757             throw new BadCommandLineException(
 758                 Messages.format(Messages.MISSING_OPERAND,optionName));
 759         }
 760         return args[i];
 761     }
 762 
 763     /**
 764      * Parses a token to a file (or a set of files)
 765      * and add them as {@link InputSource} to the specified list.
 766      *
 767      * @param suffix
 768      *      If the given token is a directory name, we do a recursive search
 769      *      and find all files that have the given suffix.
 770      */
 771     private void addFile(String name, List<InputSource> target, String suffix) throws BadCommandLineException {
 772         Object src;
 773         try {
 774             src = Util.getFileOrURL(name);
 775         } catch (IOException e) {
 776             throw new BadCommandLineException(
 777                 Messages.format(Messages.NOT_A_FILE_NOR_URL,name));
 778         }
 779         if(src instanceof URL) {
 780             target.add(absolutize(new InputSource(Util.escapeSpace(((URL)src).toExternalForm()))));
 781         } else {
 782             File fsrc = (File)src;
 783             if(fsrc.isDirectory()) {
 784                 addRecursive(fsrc,suffix,target);
 785             } else {
 786                 target.add(absolutize(fileToInputSource(fsrc)));
 787             }
 788         }
 789     }
 790 
 791     // Since javax.xml.catalog is unmodifiable we need to track catalog
 792     // URLs added and create new catalog each time addCatalog is called
 793     private final ArrayList<URI> catalogUrls = new ArrayList<>();
 794 
 795     /**
 796      * Adds a new catalog file.Use created or existed resolver to parse new catalog file.

 797      * @param catalogFile
 798      * @throws java.io.IOException
 799      */
 800     public void addCatalog(File catalogFile) throws IOException {
 801         URI newUri = catalogFile.toURI();
 802         if (!catalogUrls.contains(newUri)) {
 803             catalogUrls.add(newUri);
 804         }
 805         entityResolver = CatalogUtil.getCatalog(entityResolver, catalogFile, catalogUrls);
 806     }
 807 
 808     /**
 809      * Parses arguments and fill fields of this object.
 810      *
 811      * @param args
 812      * @exception BadCommandLineException
 813      *      thrown when there's a problem in the command-line arguments
 814      */
 815     public void parseArguments( String[] args ) throws BadCommandLineException {
 816 
 817         for (int i = 0; i < args.length; i++) {
 818             if(args[i].length()==0)
 819                 throw new BadCommandLineException();
 820             if (args[i].charAt(0) == '-') {
 821                 int j = parseArgument(args,i);
 822                 if(j==0)
 823                     throw new BadCommandLineException(
 824                         Messages.format(Messages.UNRECOGNIZED_PARAMETER, args[i]));
 825                 i += (j-1);
 826             } else {
 827                 if(args[i].endsWith(".jar"))
 828                     scanEpisodeFile(new File(args[i]));
 829                 else
 830                     addFile(args[i],grammars,".xsd");
 831             }
 832         }
 833 
 834         // configure proxy
 835         if (proxyHost != null || proxyPort != null) {
 836             if (proxyHost != null && proxyPort != null) {
 837                 System.setProperty("http.proxyHost", proxyHost);
 838                 System.setProperty("http.proxyPort", proxyPort);
 839                 System.setProperty("https.proxyHost", proxyHost);
 840                 System.setProperty("https.proxyPort", proxyPort);
 841             } else if (proxyHost == null) {
 842                 throw new BadCommandLineException(
 843                     Messages.format(Messages.MISSING_PROXYHOST));
 844             } else {
 845                 throw new BadCommandLineException(
 846                     Messages.format(Messages.MISSING_PROXYPORT));
 847             }
 848             if (proxyAuth != null) {
 849                 DefaultAuthenticator.getAuthenticator().setProxyAuth(proxyAuth);
 850             }
 851         }
 852 
 853         if (grammars.isEmpty())
 854             throw new BadCommandLineException(
 855                 Messages.format(Messages.MISSING_GRAMMAR));
 856 
 857         if( schemaLanguage==null )
 858             schemaLanguage = guessSchemaLanguage();
 859 
 860 //        if(target==SpecVersion.V2_2 && !isExtensionMode())
 861 //            throw new BadCommandLineException(
 862 //                "Currently 2.2 is still not finalized yet, so using it requires the -extension switch." +
 863 //                "NOTE THAT 2.2 SPEC MAY CHANGE BEFORE IT BECOMES FINAL.");
 864 
 865         if(pluginLoadFailure!=null)
 866             throw new BadCommandLineException(
 867                 Messages.format(Messages.PLUGIN_LOAD_FAILURE,pluginLoadFailure));
 868     }
 869 
 870     /**
 871      * Finds the {@code META-INF/sun-jaxb.episode} file to add as a binding customization.

 872      * @param jar
 873      * @throws com.sun.tools.internal.xjc.BadCommandLineException
 874      */
 875     public void scanEpisodeFile(File jar) throws BadCommandLineException {
 876         try {
 877             URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()});
 878             Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode");
 879             while (resources.hasMoreElements()) {
 880                 URL url = resources.nextElement();
 881                 addBindFile(new InputSource(url.toExternalForm()));
 882             }
 883         } catch (IOException e) {
 884             throw new BadCommandLineException(
 885                     Messages.format(Messages.FAILED_TO_LOAD,jar,e.getMessage()), e);
 886         }
 887     }
 888 
 889 
 890     /**
 891      * Guesses the schema language.

 892      * @return
 893      */
 894     public Language guessSchemaLanguage() {
 895 
 896         // otherwise, use the file extension.
 897         // not a good solution, but very easy.
 898         if ((grammars != null) && (grammars.size() > 0)) {
 899             String name = grammars.get(0).getSystemId().toLowerCase();
 900 
 901             if (name.endsWith(".dtd"))
 902                 return Language.DTD;
 903             if (name.endsWith(".wsdl"))
 904                 return Language.WSDL;
 905         }
 906 
 907         // by default, assume XML Schema
 908         return Language.XMLSCHEMA;
 909     }
 910 
 911     /**
 912      * Creates a configured CodeWriter that produces files into the specified directory.

 913      * @return
 914      * @throws java.io.IOException
 915      */
 916     public CodeWriter createCodeWriter() throws IOException {
 917         return createCodeWriter(new FileCodeWriter( targetDir, readOnly, encoding ));
 918     }
 919 
 920     /**
 921      * Creates a configured CodeWriter that produces files into the specified directory.

 922      * @param core
 923      * @return
 924      */
 925     public CodeWriter createCodeWriter( CodeWriter core ) {
 926         if(noFileHeader)
 927             return core;
 928 
 929         return new PrologCodeWriter( core,getPrologComment() );
 930     }
 931 
 932     /**
 933      * Gets the string suitable to be used as the prolog comment baked into artifacts.This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..."

 934      * @return
 935      */
 936     public String getPrologComment() {
 937         // generate format syntax: <date> 'at' <time>
 938         String format =
 939             Messages.format(Messages.DATE_FORMAT)
 940                 + " '"
 941                 + Messages.format(Messages.AT)
 942                 + "' "
 943                 + Messages.format(Messages.TIME_FORMAT);
 944         SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.ENGLISH);
 945 
 946         return Messages.format(
 947             Messages.FILE_PROLOG_COMMENT,
 948             dateFormat.format(new Date()));
 949     }
 950 
 951     /**
 952      * If a plugin failed to load, report.
 953      */
 954     private String pluginLoadFailure;
 955 
 956     /**
 957      * Looks for all "META-INF/services/[className]" files and
 958      * create one instance for each class name found inside this file.
 959      */
 960     private <T> List<T> findServices( Class<T> clazz) {
 961         final List<T> result = new ArrayList<>();
 962         final boolean debug = getDebugPropertyValue();
 963         try {
 964             // TCCL allows user plugins to be loaded even if xjc is in jdk
 965             // We have to use our SecureLoader to obtain it because we are trying to avoid SecurityException
 966             final ClassLoader tccl = SecureLoader.getContextClassLoader();
 967             final ServiceLoader<T> sl = ServiceLoader.load(clazz, tccl);
 968             for (T t : sl)
 969                 result.add(t);
 970         } catch( Throwable e ) {
 971             // ignore any error
 972             StringWriter w = new StringWriter();
 973             e.printStackTrace(new PrintWriter(w));
 974             pluginLoadFailure = w.toString();
 975             if(debug)
 976                 System.out.println(pluginLoadFailure);
 977         }
 978         return result;
 979     }
 980 
 981     private static boolean getDebugPropertyValue() {
 982         final String debugPropertyName = Options.class.getName() + ".findServices";
 983         if (System.getSecurityManager() != null) {
 984             return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
 985                 @Override
 986                 public Boolean run() {
 987                     return Boolean.getBoolean(debugPropertyName);
 988                 }
 989             });
 990         } else {
 991             return Boolean.getBoolean(debugPropertyName);
 992         }
 993     }
 994 
 995     // this is a convenient place to expose the build version to xjc plugins


  60 import com.sun.xml.internal.bind.api.impl.NameConverter;
  61 import java.net.URI;
  62 import java.net.URISyntaxException;
  63 import java.nio.charset.Charset;
  64 import java.nio.charset.IllegalCharsetNameException;
  65 import java.util.Locale;
  66 import java.util.logging.Level;
  67 import java.util.logging.Logger;
  68 
  69 import org.xml.sax.EntityResolver;
  70 import org.xml.sax.InputSource;
  71 
  72 /**
  73  * Global options.
  74  *
  75  * <p>
  76  * This class stores invocation configuration for XJC.
  77  * The configuration in this class should be abstract enough so that
  78  * it could be parsed from both command-line or Ant.
  79  */
  80 public class Options {
  81     /**
  82      * If "-debug" is specified.
  83      */
  84     public boolean debugMode;
  85 
  86     /**
  87      * If the "-verbose" option is specified.
  88      */
  89     public boolean verbose;
  90 
  91     /**
  92      * If the "-quiet" option is specified.
  93      */
  94     public boolean quiet;
  95 
  96     /**
  97      * If the -readOnly option is specified.
  98      */
  99     public boolean readOnly;
 100 
 101     /**
 102      * No file header comment (to be more friendly with diff.)
 103      */
 104     public boolean noFileHeader;
 105 
 106     /**
 107      * When on, fixes getter/setter generation to match the Bean Introspection API
 108      */
 109     public boolean enableIntrospection;
 110 
 111     /**
 112      * When on, generates content property for types with multiple xs:any derived elements (which is supposed to be correct behaviour)
 113      */
 114     public boolean contentForWildcard;
 115 
 116     /**
 117      * Encoding to be used by generated java sources, null for platform default.
 118      */
 119     public String encoding;
 120 
 121     /**
 122      * If true XML security features when parsing XML documents will be disabled.
 123      * The default value is false.
 124      * <p>
 125      * Boolean
 126      *
 127      * @since 2.2.6
 128      */
 129     public boolean disableXmlSecurity;
 130 
 131     /**
 132      * Check the source schemas with extra scrutiny.
 133      * The exact meaning depends on the schema language.
 134      */
 135     public boolean strictCheck = true;
 136 
 137     /**
 138      * If -explicit-annotation option is specified.
 139      * <p>
 140      * This generates code that works around issues specific to 1.4 runtime.
 141      */
 142     public boolean runtime14 = false;
 143 
 144     /**
 145      * If true, try to resolve name conflicts automatically by assigning mechanical numbers.
 146      */
 147     public boolean automaticNameConflictResolution = false;
 148 
 149     /**
 150      * strictly follow the compatibility rules and reject schemas that
 151      * contain features from App. E.2, use vendor binding extensions
 152      */
 153     public static final int STRICT = 1;
 154     /**
 155      * loosely follow the compatibility rules and allow the use of vendor
 156      * binding extensions
 157      */
 158     public static final int EXTENSION = 2;
 159 
 160     /**
 161      * this switch determines how carefully the compiler will follow
 162      * the compatibility rules in the spec. Either {@code STRICT}
 163      * or {@code EXTENSION}.
 164      */
 165     public int compatibilityMode = STRICT;
 166 
 167     public boolean isExtensionMode() {
 168         return compatibilityMode == EXTENSION;
 169     }
 170 
 171     private static final Logger logger = com.sun.xml.internal.bind.Util.getClassLogger();
 172 
 173     /**
 174      * Generates output for the specified version of the runtime.
 175      */
 176     public SpecVersion target = SpecVersion.LATEST;
 177 
 178 
 179     public Options() {
 180         try {
 181             Class.forName("javax.xml.bind.JAXBPermission");
 182         } catch (ClassNotFoundException cnfe) {
 183             target = SpecVersion.V2_1;
 184         }
 185     }
 186 
 187     /**
 188      * Target directory when producing files.


 276      * Used to detect if two {@link Plugin}s try to overwrite {@link #nameConverter}.
 277      */
 278     private Plugin nameConverterOwner = null;
 279 
 280     /**
 281      * Java module name in {@code module-info.java}.
 282      */
 283     private String javaModule = null;
 284 
 285     /**
 286      * Gets the active {@link FieldRendererFactory} that shall be used to build {@link Model}.
 287      *
 288      * @return always non-null.
 289      */
 290     public FieldRendererFactory getFieldRendererFactory() {
 291         return fieldRendererFactory;
 292     }
 293 
 294     /**
 295      * Sets the {@link FieldRendererFactory}.
 296      * <p>
 297      * <p>
 298      * This method is for plugins to call to set a custom {@link FieldRendererFactory}.
 299      *
 300      * @param frf   The {@link FieldRendererFactory} to be installed. Must not be null.
 301      * @param owner Identifies the plugin that owns this {@link FieldRendererFactory}.


 302      *              When two {@link Plugin}s try to call this method, this allows XJC
 303      *              to report it as a user-friendly error message.
 304      * @throws BadCommandLineException If a conflit happens, this exception carries a user-friendly error


 305      *                                 message, indicating a conflict.
 306      */
 307     public void setFieldRendererFactory(FieldRendererFactory frf, Plugin owner) throws BadCommandLineException {
 308         // since this method is for plugins, make it bit more fool-proof than usual
 309         if (frf == null)
 310             throw new IllegalArgumentException();
 311         if (fieldRendererFactoryOwner != null) {
 312             throw new BadCommandLineException(
 313                 Messages.format(Messages.FIELD_RENDERER_CONFLICT,
 314                     fieldRendererFactoryOwner.getOptionName(),
 315                     owner.getOptionName()));
 316         }
 317         this.fieldRendererFactoryOwner = owner;
 318         this.fieldRendererFactory = frf;
 319     }
 320 
 321 
 322     /**
 323      * Gets the active {@link NameConverter} that shall be used to build {@link Model}.
 324      *
 325      * @return can be null, in which case it's up to the binding.
 326      */
 327     public NameConverter getNameConverter() {
 328         return nameConverter;
 329     }
 330 
 331     /**
 332      * Sets the {@link NameConverter}.
 333      * <p>
 334      * <p>
 335      * This method is for plugins to call to set a custom {@link NameConverter}.
 336      *
 337      * @param nc    The {@link NameConverter} to be installed. Must not be null.
 338      * @param owner Identifies the plugin that owns this {@link NameConverter}.


 339      *              When two {@link Plugin}s try to call this method, this allows XJC
 340      *              to report it as a user-friendly error message.
 341      * @throws BadCommandLineException If a conflit happens, this exception carries a user-friendly error


 342      *                                 message, indicating a conflict.
 343      */
 344     public void setNameConverter(NameConverter nc, Plugin owner) throws BadCommandLineException {
 345         // since this method is for plugins, make it bit more fool-proof than usual
 346         if (nc == null)
 347             throw new IllegalArgumentException();
 348         if (nameConverter != null) {
 349             throw new BadCommandLineException(
 350                 Messages.format(Messages.NAME_CONVERTER_CONFLICT,
 351                     nameConverterOwner.getOptionName(),
 352                     owner.getOptionName()));
 353         }
 354         this.nameConverterOwner = owner;
 355         this.nameConverter = nc;
 356     }
 357 
 358     /**
 359      * Gets all the {@link Plugin}s discovered so far.
 360      * <p>
 361      * <p>
 362      * A plugins are enumerated when this method is called for the first time,
 363      * by taking {@link #classpaths} into account. That means
 364      * "-cp plugin.jar" has to come before you specify options to enable it.
 365      *
 366      * @return
 367      */
 368     public List<Plugin> getAllPlugins() {
 369         if (allPlugins == null) {
 370             allPlugins = findServices(Plugin.class);
 371         }
 372 
 373         return allPlugins;
 374     }
 375 
 376     public Language getSchemaLanguage() {
 377         if (schemaLanguage == null)
 378             schemaLanguage = guessSchemaLanguage();
 379         return schemaLanguage;
 380     }
 381 
 382     public void setSchemaLanguage(Language _schemaLanguage) {
 383         this.schemaLanguage = _schemaLanguage;
 384     }
 385 
 386     /**
 387      * Input schema files.
 388      *
 389      * @return
 390      */
 391     public InputSource[] getGrammars() {
 392         return grammars.toArray(new InputSource[grammars.size()]);
 393     }
 394 
 395     /**
 396      * Adds a new input schema.
 397      *
 398      * @param is
 399      */
 400     public void addGrammar(InputSource is) {
 401         grammars.add(absolutize(is));
 402     }
 403 
 404     private InputSource fileToInputSource(File source) {
 405         try {
 406             String url = source.toURL().toExternalForm();
 407             return new InputSource(Util.escapeSpace(url));
 408         } catch (MalformedURLException e) {
 409             return new InputSource(source.getPath());
 410         }
 411     }
 412 
 413     public void addGrammar(File source) {
 414         addGrammar(fileToInputSource(source));
 415     }
 416 
 417     /**
 418      * Recursively scan directories and add all XSD files in it.
 419      *
 420      * @param dir
 421      */
 422     public void addGrammarRecursive(File dir) {
 423         addRecursive(dir, ".xsd", grammars);
 424     }
 425 
 426     private void addRecursive(File dir, String suffix, List<InputSource> result) {
 427         File[] files = dir.listFiles();
 428         if (files == null) return; // work defensively
 429 
 430         for (File f : files) {
 431             if (f.isDirectory())
 432                 addRecursive(f, suffix, result);
 433             else if (f.getPath().endsWith(suffix))

 434                 result.add(absolutize(fileToInputSource(f)));
 435         }
 436     }
 437 
 438 
 439     private InputSource absolutize(InputSource is) {
 440         // absolutize all the system IDs in the input, so that we can map system IDs to DOM trees.
 441         try {
 442             URL baseURL = new File(".").getCanonicalFile().toURL();
 443             is.setSystemId(new URL(baseURL, is.getSystemId()).toExternalForm());
 444         } catch (IOException e) {
 445             logger.log(Level.FINE, "{0}, {1}", new Object[]{is.getSystemId(), e.getLocalizedMessage()});
 446         }
 447         return is;
 448     }
 449 
 450     /**
 451      * Input external binding files.
 452      *
 453      * @return
 454      */
 455     public InputSource[] getBindFiles() {
 456         return bindFiles.toArray(new InputSource[bindFiles.size()]);
 457     }
 458 
 459     /**
 460      * Adds a new binding file.
 461      *
 462      * @param is
 463      */
 464     public void addBindFile(InputSource is) {
 465         bindFiles.add(absolutize(is));
 466     }
 467 
 468     /**
 469      * Adds a new binding file.
 470      *
 471      * @param bindFile
 472      */
 473     public void addBindFile(File bindFile) {
 474         bindFiles.add(fileToInputSource(bindFile));
 475     }
 476 
 477     /**
 478      * Recursively scan directories and add all ".xjb" files in it.
 479      *
 480      * @param dir
 481      */
 482     public void addBindFileRecursive(File dir) {
 483         addRecursive(dir, ".xjb", bindFiles);
 484     }
 485 
 486     public final List<URL> classpaths = new ArrayList<>();
 487 
 488     /**
 489      * Gets a classLoader that can load classes specified via the
 490      * -classpath option.
 491      *
 492      * @param parent
 493      * @return
 494      */
 495     public ClassLoader getUserClassLoader(ClassLoader parent) {
 496         if (classpaths.isEmpty())
 497             return parent;
 498         return new URLClassLoader(
 499             classpaths.toArray(new URL[classpaths.size()]), parent);
 500     }
 501 
 502     /**
 503      * Gets Java module name option.
 504      *
 505      * @return Java module name option or {@code null} if this option was not set.
 506      */
 507     public String getModuleName() {
 508         return javaModule;
 509     }
 510 
 511     /**
 512      * Parses an option {@code args[i]} and return
 513      * the number of tokens consumed.
 514      *
 515      * @param args
 516      * @param i
 517      * @return 0 if the argument is not understood. Returning 0

 518      * will let the caller report an error.
 519      * @throws BadCommandLineException If the callee wants to provide a custom message for an error.

 520      */
 521     public int parseArgument(String[] args, int i) throws BadCommandLineException {
 522         if (args[i].equals("-classpath") || args[i].equals("-cp")) {
 523             String a = requireArgument(args[i], args, ++i);
 524             for (String p : a.split(File.pathSeparator)) {
 525                 File file = new File(p);
 526                 try {
 527                     classpaths.add(file.toURL());
 528                 } catch (MalformedURLException e) {
 529                     throw new BadCommandLineException(
 530                         Messages.format(Messages.NOT_A_VALID_FILENAME, file), e);
 531                 }
 532             }
 533             return 2;
 534         }
 535         if (args[i].equals("-d")) {
 536             targetDir = new File(requireArgument("-d", args, ++i));
 537             if (!targetDir.exists())
 538                 throw new BadCommandLineException(
 539                     Messages.format(Messages.NON_EXISTENT_DIR, targetDir));
 540             return 2;
 541         }
 542         if (args[i].equals("-readOnly")) {
 543             readOnly = true;
 544             return 1;
 545         }
 546         if (args[i].equals("-p")) {
 547             defaultPackage = requireArgument("-p", args, ++i);
 548             if (defaultPackage.length() == 0) { // user specified default package
 549                 // there won't be any package to annotate, so disable them
 550                 // automatically as a usability feature
 551                 packageLevelAnnotations = false;
 552             }
 553             return 2;
 554         }
 555         if (args[i].equals("-m")) {
 556             javaModule = requireArgument("-m", args, ++i);
 557             return 2;
 558         }
 559         if (args[i].equals("-debug")) {
 560             debugMode = true;
 561             verbose = true;
 562             return 1;
 563         }
 564         if (args[i].equals("-nv")) {
 565             strictCheck = false;
 566             return 1;
 567         }
 568         if (args[i].equals("-npa")) {
 569             packageLevelAnnotations = false;
 570             return 1;
 571         }
 572         if (args[i].equals("-no-header")) {
 573             noFileHeader = true;
 574             return 1;
 575         }
 576         if (args[i].equals("-verbose")) {
 577             verbose = true;
 578             return 1;
 579         }
 580         if (args[i].equals("-quiet")) {
 581             quiet = true;
 582             return 1;
 583         }
 584         if (args[i].equals("-XexplicitAnnotation")) {
 585             runtime14 = true;
 586             return 1;
 587         }
 588         if (args[i].equals("-enableIntrospection")) {
 589             enableIntrospection = true;
 590             return 1;
 591         }
 592         if (args[i].equals("-disableXmlSecurity")) {
 593             disableXmlSecurity = true;
 594             return 1;
 595         }
 596         if (args[i].equals("-contentForWildcard")) {
 597             contentForWildcard = true;
 598             return 1;
 599         }
 600         if (args[i].equals("-XautoNameResolution")) {
 601             automaticNameConflictResolution = true;
 602             return 1;
 603         }
 604         if (args[i].equals("-b")) {
 605             addFile(requireArgument("-b", args, ++i), bindFiles, ".xjb");
 606             return 2;
 607         }
 608         if (args[i].equals("-dtd")) {
 609             schemaLanguage = Language.DTD;
 610             return 1;
 611         }
 612         if (args[i].equals("-xmlschema")) {
 613             schemaLanguage = Language.XMLSCHEMA;
 614             return 1;
 615         }
 616         if (args[i].equals("-wsdl")) {
 617             schemaLanguage = Language.WSDL;
 618             return 1;
 619         }
 620         if (args[i].equals("-extension")) {
 621             compatibilityMode = EXTENSION;
 622             return 1;
 623         }
 624         if (args[i].equals("-target")) {
 625             String token = requireArgument("-target", args, ++i);
 626             target = SpecVersion.parse(token);
 627             if (target == null)
 628                 throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_TARGET_VERSION, token));
 629             return 2;
 630         }
 631         if (args[i].equals("-httpproxyfile")) {
 632             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
 633                 throw new BadCommandLineException(
 634                     Messages.format(Messages.MISSING_PROXYFILE));
 635             }
 636 
 637             File file = new File(args[++i]);
 638             if (!file.exists()) {
 639                 throw new BadCommandLineException(
 640                     Messages.format(Messages.NO_SUCH_FILE, file));
 641             }
 642 
 643             try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
 644                 parseProxy(in.readLine());
 645             } catch (IOException e) {
 646                 throw new BadCommandLineException(
 647                     Messages.format(Messages.FAILED_TO_PARSE, file, e.getMessage()), e);
 648             }
 649 
 650             return 2;
 651         }
 652         if (args[i].equals("-httpproxy")) {
 653             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
 654                 throw new BadCommandLineException(
 655                     Messages.format(Messages.MISSING_PROXY));
 656             }
 657 
 658             parseProxy(args[++i]);
 659             return 2;
 660         }
 661         if (args[i].equals("-host")) {
 662             proxyHost = requireArgument("-host", args, ++i);
 663             return 2;
 664         }
 665         if (args[i].equals("-port")) {
 666             proxyPort = requireArgument("-port", args, ++i);
 667             return 2;
 668         }
 669         if (args[i].equals("-catalog")) {
 670             // use Sun's "XML Entity and URI Resolvers" by Norman Walsh
 671             // to resolve external entities.
 672             // https://xerces.apache.org/xml-commons/components/resolver/resolver-article.html
 673 
 674             File catalogFile = new File(requireArgument("-catalog", args, ++i));
 675             try {
 676                 addCatalog(catalogFile);
 677             } catch (IOException e) {
 678                 throw new BadCommandLineException(
 679                     Messages.format(Messages.FAILED_TO_PARSE, catalogFile, e.getMessage()), e);
 680             }
 681             return 2;
 682         }
 683         if (args[i].equals("-Xtest-class-name-allocator")) {
 684             classNameAllocator = new ClassNameAllocator() {
 685                 @Override
 686                 public String assignClassName(String packageName, String className) {
 687                     System.out.printf("assignClassName(%s,%s)\n", packageName, className);
 688                     return className + "_Type";
 689                 }
 690             };
 691             return 1;
 692         }
 693 
 694         if (args[i].equals("-encoding")) {
 695             encoding = requireArgument("-encoding", args, ++i);
 696             try {
 697                 if (!Charset.isSupported(encoding)) {
 698                     throw new BadCommandLineException(
 699                         Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
 700                 }
 701             } catch (IllegalCharsetNameException icne) {
 702                 throw new BadCommandLineException(
 703                     Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
 704             }
 705             return 2;
 706         }
 707 
 708         // see if this is one of the extensions
 709         for (Plugin plugin : getAllPlugins()) {
 710             try {
 711                 if (('-' + plugin.getOptionName()).equals(args[i])) {
 712                     activePlugins.add(plugin);
 713                     plugin.onActivated(this);
 714                     pluginURIs.addAll(plugin.getCustomizationURIs());
 715 
 716                     // give the plugin a chance to parse arguments to this option.
 717                     // this is new in 2.1, and due to the backward compatibility reason,
 718                     // if plugin didn't understand it, we still return 1 to indicate
 719                     // that this option is consumed.
 720                     int r = plugin.parseArgument(this, args, i);
 721                     if (r != 0)
 722                         return r;
 723                     else
 724                         return 1;
 725                 }
 726 
 727                 int r = plugin.parseArgument(this, args, i);
 728                 if (r != 0) return r;
 729             } catch (IOException e) {
 730                 throw new BadCommandLineException(e.getMessage(), e);
 731             }
 732         }
 733 
 734         return 0;   // unrecognized
 735     }
 736 
 737     private void parseProxy(String text) throws BadCommandLineException {
 738         int i = text.lastIndexOf('@');
 739         int j = text.lastIndexOf(':');
 740 
 741         if (i > 0) {
 742             proxyAuth = text.substring(0, i);
 743             if (j > i) {
 744                 proxyHost = text.substring(i + 1, j);
 745                 proxyPort = text.substring(j + 1);
 746             } else {
 747                 proxyHost = text.substring(i + 1);
 748                 proxyPort = "80";
 749             }
 750         } else {
 751             //no auth info
 752             if (j < 0) {
 753                 //no port
 754                 proxyHost = text;
 755                 proxyPort = "80";
 756             } else {
 757                 proxyHost = text.substring(0, j);
 758                 proxyPort = text.substring(j + 1);
 759             }
 760         }
 761         try {
 762             Integer.valueOf(proxyPort);
 763         } catch (NumberFormatException e) {
 764             throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY, text));
 765         }
 766     }
 767 
 768     /**
 769      * Obtains an operand and reports an error if it's not there.
 770      *
 771      * @param optionName
 772      * @param args
 773      * @param i
 774      * @return
 775      * @throws com.sun.tools.internal.xjc.BadCommandLineException
 776      */
 777     public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException {
 778         if (i == args.length || args[i].startsWith("-")) {
 779             throw new BadCommandLineException(
 780                 Messages.format(Messages.MISSING_OPERAND, optionName));
 781         }
 782         return args[i];
 783     }
 784 
 785     /**
 786      * Parses a token to a file (or a set of files)
 787      * and add them as {@link InputSource} to the specified list.
 788      *
 789      * @param suffix If the given token is a directory name, we do a recursive search

 790      *               and find all files that have the given suffix.
 791      */
 792     private void addFile(String name, List<InputSource> target, String suffix) throws BadCommandLineException {
 793         Object src;
 794         try {
 795             src = Util.getFileOrURL(name);
 796         } catch (IOException e) {
 797             throw new BadCommandLineException(
 798                 Messages.format(Messages.NOT_A_FILE_NOR_URL, name));
 799         }
 800         if (src instanceof URL) {
 801             target.add(absolutize(new InputSource(Util.escapeSpace(((URL) src).toExternalForm()))));
 802         } else {
 803             File fsrc = (File) src;
 804             if (fsrc.isDirectory()) {
 805                 addRecursive(fsrc, suffix, target);
 806             } else {
 807                 target.add(absolutize(fileToInputSource(fsrc)));
 808             }
 809         }
 810     }
 811 
 812     // Since javax.xml.catalog is unmodifiable we need to track catalog
 813     // URLs added and create new catalog each time addCatalog is called
 814     private final ArrayList<URI> catalogUrls = new ArrayList<>();
 815 
 816     /**
 817      * Adds a new catalog file.Use created or existed resolver to parse new catalog file.
 818      *
 819      * @param catalogFile
 820      * @throws java.io.IOException
 821      */
 822     public void addCatalog(File catalogFile) throws IOException {
 823         URI newUri = catalogFile.toURI();
 824         if (!catalogUrls.contains(newUri)) {
 825             catalogUrls.add(newUri);
 826         }
 827         entityResolver = CatalogUtil.getCatalog(entityResolver, catalogFile, catalogUrls);
 828     }
 829 
 830     /**
 831      * Parses arguments and fill fields of this object.
 832      *
 833      * @param args
 834      * @throws BadCommandLineException thrown when there's a problem in the command-line arguments

 835      */
 836     public void parseArguments(String[] args) throws BadCommandLineException {
 837 
 838         for (int i = 0; i < args.length; i++) {
 839             if (args[i].length() == 0)
 840                 throw new BadCommandLineException();
 841             if (args[i].charAt(0) == '-') {
 842                 int j = parseArgument(args, i);
 843                 if (j == 0)
 844                     throw new BadCommandLineException(
 845                         Messages.format(Messages.UNRECOGNIZED_PARAMETER, args[i]));
 846                 i += (j - 1);
 847             } else {
 848                 if (args[i].endsWith(".jar"))
 849                     scanEpisodeFile(new File(args[i]));
 850                 else
 851                     addFile(args[i], grammars, ".xsd");
 852             }
 853         }
 854 
 855         // configure proxy
 856         if (proxyHost != null || proxyPort != null) {
 857             if (proxyHost != null && proxyPort != null) {
 858                 System.setProperty("http.proxyHost", proxyHost);
 859                 System.setProperty("http.proxyPort", proxyPort);
 860                 System.setProperty("https.proxyHost", proxyHost);
 861                 System.setProperty("https.proxyPort", proxyPort);
 862             } else if (proxyHost == null) {
 863                 throw new BadCommandLineException(
 864                     Messages.format(Messages.MISSING_PROXYHOST));
 865             } else {
 866                 throw new BadCommandLineException(
 867                     Messages.format(Messages.MISSING_PROXYPORT));
 868             }
 869             if (proxyAuth != null) {
 870                 DefaultAuthenticator.getAuthenticator().setProxyAuth(proxyAuth);
 871             }
 872         }
 873 
 874         if (grammars.isEmpty())
 875             throw new BadCommandLineException(
 876                 Messages.format(Messages.MISSING_GRAMMAR));
 877 
 878         if (schemaLanguage == null)
 879             schemaLanguage = guessSchemaLanguage();
 880 
 881 //        if(target==SpecVersion.V2_2 && !isExtensionMode())
 882 //            throw new BadCommandLineException(
 883 //                "Currently 2.2 is still not finalized yet, so using it requires the -extension switch." +
 884 //                "NOTE THAT 2.2 SPEC MAY CHANGE BEFORE IT BECOMES FINAL.");
 885 
 886         if (pluginLoadFailure != null)
 887             throw new BadCommandLineException(
 888                 Messages.format(Messages.PLUGIN_LOAD_FAILURE, pluginLoadFailure));
 889     }
 890 
 891     /**
 892      * Finds the {@code META-INF/sun-jaxb.episode} file to add as a binding customization.
 893      *
 894      * @param jar
 895      * @throws com.sun.tools.internal.xjc.BadCommandLineException
 896      */
 897     public void scanEpisodeFile(File jar) throws BadCommandLineException {
 898         try {
 899             URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()});
 900             Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode");
 901             while (resources.hasMoreElements()) {
 902                 URL url = resources.nextElement();
 903                 addBindFile(new InputSource(url.toExternalForm()));
 904             }
 905         } catch (IOException e) {
 906             throw new BadCommandLineException(
 907                 Messages.format(Messages.FAILED_TO_LOAD, jar, e.getMessage()), e);
 908         }
 909     }
 910 
 911 
 912     /**
 913      * Guesses the schema language.
 914      *
 915      * @return
 916      */
 917     public Language guessSchemaLanguage() {
 918 
 919         // otherwise, use the file extension.
 920         // not a good solution, but very easy.
 921         if ((grammars != null) && (grammars.size() > 0)) {
 922             String name = grammars.get(0).getSystemId().toLowerCase();
 923 
 924             if (name.endsWith(".dtd"))
 925                 return Language.DTD;
 926             if (name.endsWith(".wsdl"))
 927                 return Language.WSDL;
 928         }
 929 
 930         // by default, assume XML Schema
 931         return Language.XMLSCHEMA;
 932     }
 933 
 934     /**
 935      * Creates a configured CodeWriter that produces files into the specified directory.
 936      *
 937      * @return
 938      * @throws java.io.IOException
 939      */
 940     public CodeWriter createCodeWriter() throws IOException {
 941         return createCodeWriter(new FileCodeWriter(targetDir, readOnly, encoding));
 942     }
 943 
 944     /**
 945      * Creates a configured CodeWriter that produces files into the specified directory.
 946      *
 947      * @param core
 948      * @return
 949      */
 950     public CodeWriter createCodeWriter(CodeWriter core) {
 951         if (noFileHeader)
 952             return core;
 953 
 954         return new PrologCodeWriter(core, getPrologComment());
 955     }
 956 
 957     /**
 958      * Gets the string suitable to be used as the prolog comment baked into artifacts.This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..."
 959      *
 960      * @return
 961      */
 962     public String getPrologComment() {
 963         // generate format syntax: <date> 'at' <time>
 964         String format =
 965             Messages.format(Messages.DATE_FORMAT)
 966                 + " '"
 967                 + Messages.format(Messages.AT)
 968                 + "' "
 969                 + Messages.format(Messages.TIME_FORMAT);
 970         SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.ENGLISH);
 971 
 972         return Messages.format(
 973             Messages.FILE_PROLOG_COMMENT,
 974             dateFormat.format(new Date()));
 975     }
 976 
 977     /**
 978      * If a plugin failed to load, report.
 979      */
 980     private String pluginLoadFailure;
 981 
 982     /**
 983      * Looks for all "META-INF/services/[className]" files and
 984      * create one instance for each class name found inside this file.
 985      */
 986     private <T> List<T> findServices(Class<T> clazz) {
 987         final List<T> result = new ArrayList<>();
 988         final boolean debug = getDebugPropertyValue();
 989         try {
 990             // TCCL allows user plugins to be loaded even if xjc is in jdk
 991             // We have to use our SecureLoader to obtain it because we are trying to avoid SecurityException
 992             final ClassLoader tccl = SecureLoader.getContextClassLoader();
 993             final ServiceLoader<T> sl = ServiceLoader.load(clazz, tccl);
 994             for (T t : sl)
 995                 result.add(t);
 996         } catch (Throwable e) {
 997             // ignore any error
 998             StringWriter w = new StringWriter();
 999             e.printStackTrace(new PrintWriter(w));
1000             pluginLoadFailure = w.toString();
1001             if (debug)
1002                 System.out.println(pluginLoadFailure);
1003         }
1004         return result;
1005     }
1006 
1007     private static boolean getDebugPropertyValue() {
1008         final String debugPropertyName = Options.class.getName() + ".findServices";
1009         if (System.getSecurityManager() != null) {
1010             return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1011                 @Override
1012                 public Boolean run() {
1013                     return Boolean.getBoolean(debugPropertyName);
1014                 }
1015             });
1016         } else {
1017             return Boolean.getBoolean(debugPropertyName);
1018         }
1019     }
1020 
1021     // this is a convenient place to expose the build version to xjc plugins
< prev index next >