src/share/jaxws_classes/com/sun/tools/internal/xjc/Options.java

Thu, 31 Aug 2017 15:18:52 +0800

author
aoqi
date
Thu, 31 Aug 2017 15:18:52 +0800
changeset 637
9c07ef4934dd
parent 368
0989ad8c0860
parent 0
373ffda63c9a
permissions
-rw-r--r--

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.BufferedReader;
    29 import java.io.File;
    30 import java.io.FileInputStream;
    31 import java.io.IOException;
    32 import java.io.InputStreamReader;
    33 import java.io.PrintWriter;
    34 import java.io.StringWriter;
    35 import java.lang.reflect.Array;
    36 import java.lang.reflect.InvocationTargetException;
    37 import java.net.MalformedURLException;
    38 import java.net.URL;
    39 import java.net.URLClassLoader;
    40 import java.text.SimpleDateFormat;
    41 import java.util.ArrayList;
    42 import java.util.Arrays;
    43 import java.util.Date;
    44 import java.util.Enumeration;
    45 import java.util.HashSet;
    46 import java.util.List;
    47 import java.util.Set;
    49 import com.sun.codemodel.internal.CodeWriter;
    50 import com.sun.codemodel.internal.JPackage;
    51 import com.sun.codemodel.internal.JResourceFile;
    52 import com.sun.codemodel.internal.writer.FileCodeWriter;
    53 import com.sun.codemodel.internal.writer.PrologCodeWriter;
    54 import com.sun.istack.internal.tools.DefaultAuthenticator;
    55 import com.sun.org.apache.xml.internal.resolver.CatalogManager;
    56 import com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver;
    57 import com.sun.tools.internal.xjc.api.ClassNameAllocator;
    58 import com.sun.tools.internal.xjc.api.SpecVersion;
    59 import com.sun.tools.internal.xjc.generator.bean.field.FieldRendererFactory;
    60 import com.sun.tools.internal.xjc.model.Model;
    61 import com.sun.tools.internal.xjc.reader.Util;
    62 import com.sun.xml.internal.bind.api.impl.NameConverter;
    63 import java.net.URI;
    64 import java.net.URISyntaxException;
    65 import java.nio.charset.Charset;
    66 import java.nio.charset.IllegalCharsetNameException;
    67 import java.util.Locale;
    68 import java.util.logging.Level;
    69 import java.util.logging.Logger;
    71 import org.xml.sax.EntityResolver;
    72 import org.xml.sax.InputSource;
    74 /**
    75  * Global options.
    76  *
    77  * <p>
    78  * This class stores invocation configuration for XJC.
    79  * The configuration in this class should be abstract enough so that
    80  * it could be parsed from both command-line or Ant.
    81  */
    82 public class Options
    83 {
    84     /** If "-debug" is specified. */
    85     public boolean debugMode;
    87     /** If the "-verbose" option is specified. */
    88     public boolean verbose;
    90     /** If the "-quiet" option is specified. */
    91     public boolean quiet;
    93     /** If the -readOnly option is specified. */
    94     public boolean readOnly;
    96     /** No file header comment (to be more friendly with diff.) */
    97     public boolean noFileHeader;
    99     /** When on, fixes getter/setter generation to match the Bean Introspection API */
   100     public boolean enableIntrospection;
   102     /** When on, generates content property for types with multiple xs:any derived elements (which is supposed to be correct behaviour) */
   103     public boolean contentForWildcard;
   105     /** Encoding to be used by generated java sources, null for platform default. */
   106     public String encoding;
   108     /**
   109      * If true XML security features when parsing XML documents will be disabled.
   110      * The default value is false.
   111      *
   112      * Boolean
   113      * @since 2.2.6
   114      */
   115     public boolean disableXmlSecurity;
   117     /**
   118      * Check the source schemas with extra scrutiny.
   119      * The exact meaning depends on the schema language.
   120      */
   121     public boolean strictCheck =true;
   123     /**
   124      * If -explicit-annotation option is specified.
   125      * <p>
   126      * This generates code that works around issues specific to 1.4 runtime.
   127      */
   128     public boolean runtime14 = false;
   130     /**
   131      * If true, try to resolve name conflicts automatically by assigning mechanical numbers.
   132      */
   133     public boolean automaticNameConflictResolution = false;
   135     /**
   136      * strictly follow the compatibility rules and reject schemas that
   137      * contain features from App. E.2, use vendor binding extensions
   138      */
   139     public static final int STRICT = 1;
   140     /**
   141      * loosely follow the compatibility rules and allow the use of vendor
   142      * binding extensions
   143      */
   144     public static final int EXTENSION = 2;
   146     /**
   147      * this switch determines how carefully the compiler will follow
   148      * the compatibility rules in the spec. Either <code>STRICT</code>
   149      * or <code>EXTENSION</code>.
   150      */
   151     public int compatibilityMode = STRICT;
   153     public boolean isExtensionMode() {
   154         return compatibilityMode==EXTENSION;
   155     }
   157     private static final Logger logger = com.sun.xml.internal.bind.Util.getClassLogger();
   159     /**
   160      * Generates output for the specified version of the runtime.
   161      */
   162     public SpecVersion target = SpecVersion.LATEST;
   165     public Options() {
   166         try {
   167             Class.forName("javax.xml.bind.JAXBPermission");
   168         } catch (ClassNotFoundException cnfe) {
   169             target = SpecVersion.V2_1;
   170         }
   171     }
   173     /**
   174      * Target directory when producing files.
   175      * <p>
   176      * This field is not used when XJC is driven through the XJC API.
   177      * Plugins that need to generate extra files should do so by using
   178      * {@link JPackage#addResourceFile(JResourceFile)}.
   179      */
   180     public File targetDir = new File(".");
   182     /**
   183      * Actually stores {@link CatalogResolver}, but the field
   184      * type is made to {@link EntityResolver} so that XJC can be
   185      * used even if resolver.jar is not available in the classpath.
   186      */
   187     public EntityResolver entityResolver = null;
   189     /**
   190      * Type of input schema language. One of the <code>SCHEMA_XXX</code>
   191      * constants.
   192      */
   193     private Language schemaLanguage = null;
   195     /**
   196      * The -p option that should control the default Java package that
   197      * will contain the generated code. Null if unspecified.
   198      */
   199     public String defaultPackage = null;
   201     /**
   202      * Similar to the -p option, but this one works with a lower priority,
   203      * and customizations overrides this. Used by JAX-RPC.
   204      */
   205     public String defaultPackage2 = null;
   207     /**
   208      * Input schema files as a list of {@link InputSource}s.
   209      */
   210     private final List<InputSource> grammars = new ArrayList<InputSource>();
   212     private final List<InputSource> bindFiles = new ArrayList<InputSource>();
   214     // Proxy setting.
   215     private String proxyHost = null;
   216     private String proxyPort = null;
   217     public String proxyAuth = null;
   219     /**
   220      * {@link Plugin}s that are enabled in this compilation.
   221      */
   222     public final List<Plugin> activePlugins = new ArrayList<Plugin>();
   224     /**
   225      * All discovered {@link Plugin}s.
   226      * This is lazily parsed, so that we can take '-cp' option into account.
   227      *
   228      * @see #getAllPlugins()
   229      */
   230     private List<Plugin> allPlugins;
   232     /**
   233      * Set of URIs that plug-ins recognize as extension bindings.
   234      */
   235     public final Set<String> pluginURIs = new HashSet<String>();
   237     /**
   238      * This allocator has the final say on deciding the class name.
   239      */
   240     public ClassNameAllocator classNameAllocator;
   242     /**
   243      * This switch controls whether or not xjc will generate package level annotations
   244      */
   245     public boolean packageLevelAnnotations = true;
   247     /**
   248      * This {@link FieldRendererFactory} determines how the fields are generated.
   249      */
   250     private FieldRendererFactory fieldRendererFactory = new FieldRendererFactory();
   251     /**
   252      * Used to detect if two {@link Plugin}s try to overwrite {@link #fieldRendererFactory}.
   253      */
   254     private Plugin fieldRendererFactoryOwner = null;
   256     /**
   257      * If this is non-null, we use this {@link NameConverter} over the one
   258      * given in the schema/binding.
   259      */
   260     private NameConverter nameConverter = null;
   261     /**
   262      * Used to detect if two {@link Plugin}s try to overwrite {@link #nameConverter}.
   263      */
   264     private Plugin nameConverterOwner = null;
   266     /**
   267      * Gets the active {@link FieldRendererFactory} that shall be used to build {@link Model}.
   268      *
   269      * @return always non-null.
   270      */
   271     public FieldRendererFactory getFieldRendererFactory() {
   272         return fieldRendererFactory;
   273     }
   275     /**
   276      * Sets the {@link FieldRendererFactory}.
   277      *
   278      * <p>
   279      * This method is for plugins to call to set a custom {@link FieldRendererFactory}.
   280      *
   281      * @param frf
   282      *      The {@link FieldRendererFactory} to be installed. Must not be null.
   283      * @param owner
   284      *      Identifies the plugin that owns this {@link FieldRendererFactory}.
   285      *      When two {@link Plugin}s try to call this method, this allows XJC
   286      *      to report it as a user-friendly error message.
   287      *
   288      * @throws BadCommandLineException
   289      *      If a conflit happens, this exception carries a user-friendly error
   290      *      message, indicating a conflict.
   291      */
   292     public void setFieldRendererFactory(FieldRendererFactory frf, Plugin owner) throws BadCommandLineException {
   293         // since this method is for plugins, make it bit more fool-proof than usual
   294         if(frf==null)
   295             throw new IllegalArgumentException();
   296         if(fieldRendererFactoryOwner!=null) {
   297             throw new BadCommandLineException(
   298                 Messages.format(Messages.FIELD_RENDERER_CONFLICT,
   299                     fieldRendererFactoryOwner.getOptionName(),
   300                     owner.getOptionName() ));
   301         }
   302         this.fieldRendererFactoryOwner = owner;
   303         this.fieldRendererFactory = frf;
   304     }
   307     /**
   308      * Gets the active {@link NameConverter} that shall be used to build {@link Model}.
   309      *
   310      * @return can be null, in which case it's up to the binding.
   311      */
   312     public NameConverter getNameConverter() {
   313         return nameConverter;
   314     }
   316     /**
   317      * Sets the {@link NameConverter}.
   318      *
   319      * <p>
   320      * This method is for plugins to call to set a custom {@link NameConverter}.
   321      *
   322      * @param nc
   323      *      The {@link NameConverter} to be installed. Must not be null.
   324      * @param owner
   325      *      Identifies the plugin that owns this {@link NameConverter}.
   326      *      When two {@link Plugin}s try to call this method, this allows XJC
   327      *      to report it as a user-friendly error message.
   328      *
   329      * @throws BadCommandLineException
   330      *      If a conflit happens, this exception carries a user-friendly error
   331      *      message, indicating a conflict.
   332      */
   333     public void setNameConverter(NameConverter nc, Plugin owner) throws BadCommandLineException {
   334         // since this method is for plugins, make it bit more fool-proof than usual
   335         if(nc==null)
   336             throw new IllegalArgumentException();
   337         if(nameConverter!=null) {
   338             throw new BadCommandLineException(
   339                 Messages.format(Messages.NAME_CONVERTER_CONFLICT,
   340                     nameConverterOwner.getOptionName(),
   341                     owner.getOptionName() ));
   342         }
   343         this.nameConverterOwner = owner;
   344         this.nameConverter = nc;
   345     }
   347     /**
   348      * Gets all the {@link Plugin}s discovered so far.
   349      *
   350      * <p>
   351      * A plugins are enumerated when this method is called for the first time,
   352      * by taking {@link #classpaths} into account. That means
   353      * "-cp plugin.jar" has to come before you specify options to enable it.
   354      */
   355     public List<Plugin> getAllPlugins() {
   356         if(allPlugins==null) {
   357             allPlugins = new ArrayList<Plugin>();
   358             ClassLoader ucl = getUserClassLoader(SecureLoader.getClassClassLoader(getClass()));
   359             allPlugins.addAll(Arrays.asList(findServices(Plugin.class,ucl)));
   360         }
   362         return allPlugins;
   363     }
   365     public Language getSchemaLanguage() {
   366         if( schemaLanguage==null)
   367             schemaLanguage = guessSchemaLanguage();
   368         return schemaLanguage;
   369     }
   370     public void setSchemaLanguage(Language _schemaLanguage) {
   371         this.schemaLanguage = _schemaLanguage;
   372     }
   374     /** Input schema files. */
   375     public InputSource[] getGrammars() {
   376         return grammars.toArray(new InputSource[grammars.size()]);
   377     }
   379     /**
   380      * Adds a new input schema.
   381      */
   382     public void addGrammar( InputSource is ) {
   383         grammars.add(absolutize(is));
   384     }
   386     private InputSource fileToInputSource( File source ) {
   387         try {
   388             String url = source.toURL().toExternalForm();
   389             return new InputSource(Util.escapeSpace(url));
   390         } catch (MalformedURLException e) {
   391             return new InputSource(source.getPath());
   392         }
   393     }
   395     public void addGrammar( File source ) {
   396         addGrammar(fileToInputSource(source));
   397     }
   399     /**
   400      * Recursively scan directories and add all XSD files in it.
   401      */
   402     public void addGrammarRecursive( File dir ) {
   403         addRecursive(dir,".xsd",grammars);
   404     }
   406     private  void addRecursive( File dir, String suffix, List<InputSource> result ) {
   407         File[] files = dir.listFiles();
   408         if(files==null)     return; // work defensively
   410         for( File f : files ) {
   411             if(f.isDirectory())
   412                 addRecursive(f,suffix,result);
   413             else
   414             if(f.getPath().endsWith(suffix))
   415                 result.add(absolutize(fileToInputSource(f)));
   416         }
   417     }
   420     private InputSource absolutize(InputSource is) {
   421         // absolutize all the system IDs in the input, so that we can map system IDs to DOM trees.
   422         try {
   423             URL baseURL = new File(".").getCanonicalFile().toURL();
   424             is.setSystemId( new URL(baseURL,is.getSystemId()).toExternalForm() );
   425         } catch( IOException e ) {
   426             logger.log(Level.FINE, "{0}, {1}", new Object[]{is.getSystemId(), e.getLocalizedMessage()});
   427         }
   428         return is;
   429     }
   431     /** Input external binding files. */
   432     public InputSource[] getBindFiles() {
   433         return bindFiles.toArray(new InputSource[bindFiles.size()]);
   434     }
   436     /**
   437      * Adds a new binding file.
   438      */
   439     public void addBindFile( InputSource is ) {
   440         bindFiles.add(absolutize(is));
   441     }
   443     /**
   444      * Adds a new binding file.
   445      */
   446     public void addBindFile( File bindFile ) {
   447         bindFiles.add(fileToInputSource(bindFile));
   448     }
   450     /**
   451      * Recursively scan directories and add all ".xjb" files in it.
   452      */
   453     public void addBindFileRecursive( File dir ) {
   454         addRecursive(dir,".xjb",bindFiles);
   455     }
   457     public final List<URL> classpaths = new ArrayList<URL>();
   458     /**
   459      * Gets a classLoader that can load classes specified via the
   460      * -classpath option.
   461      */
   462     public ClassLoader getUserClassLoader( ClassLoader parent ) {
   463         if (classpaths.isEmpty())
   464             return parent;
   465         return new URLClassLoader(
   466                 classpaths.toArray(new URL[classpaths.size()]),parent);
   467     }
   470     /**
   471      * Parses an option <code>args[i]</code> and return
   472      * the number of tokens consumed.
   473      *
   474      * @return
   475      *      0 if the argument is not understood. Returning 0
   476      *      will let the caller report an error.
   477      * @exception BadCommandLineException
   478      *      If the callee wants to provide a custom message for an error.
   479      */
   480     public int parseArgument( String[] args, int i ) throws BadCommandLineException {
   481         if (args[i].equals("-classpath") || args[i].equals("-cp")) {
   482             String a = requireArgument(args[i], args, ++i);
   483             for (String p : a.split(File.pathSeparator)) {
   484                 File file = new File(p);
   485                 try {
   486                     classpaths.add(file.toURL());
   487                 } catch (MalformedURLException e) {
   488                     throw new BadCommandLineException(
   489                         Messages.format(Messages.NOT_A_VALID_FILENAME,file),e);
   490                 }
   491             }
   492             return 2;
   493         }
   494         if (args[i].equals("-d")) {
   495             targetDir = new File(requireArgument("-d",args,++i));
   496             if( !targetDir.exists() )
   497                 throw new BadCommandLineException(
   498                     Messages.format(Messages.NON_EXISTENT_DIR,targetDir));
   499             return 2;
   500         }
   501         if (args[i].equals("-readOnly")) {
   502             readOnly = true;
   503             return 1;
   504         }
   505         if (args[i].equals("-p")) {
   506             defaultPackage = requireArgument("-p",args,++i);
   507             if(defaultPackage.length()==0) { // user specified default package
   508                 // there won't be any package to annotate, so disable them
   509                 // automatically as a usability feature
   510                 packageLevelAnnotations = false;
   511             }
   512             return 2;
   513         }
   514         if (args[i].equals("-debug")) {
   515             debugMode = true;
   516             verbose = true;
   517             return 1;
   518         }
   519         if (args[i].equals("-nv")) {
   520             strictCheck = false;
   521             return 1;
   522         }
   523         if( args[i].equals("-npa")) {
   524             packageLevelAnnotations = false;
   525             return 1;
   526         }
   527         if( args[i].equals("-no-header")) {
   528             noFileHeader = true;
   529             return 1;
   530         }
   531         if (args[i].equals("-verbose")) {
   532             verbose = true;
   533             return 1;
   534         }
   535         if (args[i].equals("-quiet")) {
   536             quiet = true;
   537             return 1;
   538         }
   539         if (args[i].equals("-XexplicitAnnotation")) {
   540             runtime14 = true;
   541             return 1;
   542         }
   543         if (args[i].equals("-enableIntrospection")) {
   544             enableIntrospection = true;
   545             return 1;
   546         }
   547         if (args[i].equals("-disableXmlSecurity")) {
   548             disableXmlSecurity = true;
   549             return 1;
   550         }
   551         if (args[i].equals("-contentForWildcard")) {
   552             contentForWildcard = true;
   553             return 1;
   554         }
   555         if (args[i].equals("-XautoNameResolution")) {
   556             automaticNameConflictResolution = true;
   557             return 1;
   558         }
   559         if (args[i].equals("-b")) {
   560             addFile(requireArgument("-b",args,++i),bindFiles,".xjb");
   561             return 2;
   562         }
   563         if (args[i].equals("-dtd")) {
   564             schemaLanguage = Language.DTD;
   565             return 1;
   566         }
   567         if (args[i].equals("-relaxng")) {
   568             schemaLanguage = Language.RELAXNG;
   569             return 1;
   570         }
   571         if (args[i].equals("-relaxng-compact")) {
   572             schemaLanguage = Language.RELAXNG_COMPACT;
   573             return 1;
   574         }
   575         if (args[i].equals("-xmlschema")) {
   576             schemaLanguage = Language.XMLSCHEMA;
   577             return 1;
   578         }
   579         if (args[i].equals("-wsdl")) {
   580             schemaLanguage = Language.WSDL;
   581             return 1;
   582         }
   583         if (args[i].equals("-extension")) {
   584             compatibilityMode = EXTENSION;
   585             return 1;
   586         }
   587         if (args[i].equals("-target")) {
   588             String token = requireArgument("-target",args,++i);
   589             target = SpecVersion.parse(token);
   590             if(target==null)
   591                 throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_TARGET_VERSION,token));
   592             return 2;
   593         }
   594         if (args[i].equals("-httpproxyfile")) {
   595             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
   596                 throw new BadCommandLineException(
   597                     Messages.format(Messages.MISSING_PROXYFILE));
   598             }
   600             File file = new File(args[++i]);
   601             if(!file.exists()) {
   602                 throw new BadCommandLineException(
   603                     Messages.format(Messages.NO_SUCH_FILE,file));
   604             }
   606             try {
   607                 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
   608                 parseProxy(in.readLine());
   609                 in.close();
   610             } catch (IOException e) {
   611                 throw new BadCommandLineException(
   612                     Messages.format(Messages.FAILED_TO_PARSE,file,e.getMessage()),e);
   613             }
   615             return 2;
   616         }
   617         if (args[i].equals("-httpproxy")) {
   618             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
   619                 throw new BadCommandLineException(
   620                     Messages.format(Messages.MISSING_PROXY));
   621             }
   623             parseProxy(args[++i]);
   624             return 2;
   625         }
   626         if (args[i].equals("-host")) {
   627             proxyHost = requireArgument("-host",args,++i);
   628             return 2;
   629         }
   630         if (args[i].equals("-port")) {
   631             proxyPort = requireArgument("-port",args,++i);
   632             return 2;
   633         }
   634         if( args[i].equals("-catalog") ) {
   635             // use Sun's "XML Entity and URI Resolvers" by Norman Walsh
   636             // to resolve external entities.
   637             // http://www.sun.com/xml/developers/resolver/
   639             File catalogFile = new File(requireArgument("-catalog",args,++i));
   640             try {
   641                 addCatalog(catalogFile);
   642             } catch (IOException e) {
   643                 throw new BadCommandLineException(
   644                     Messages.format(Messages.FAILED_TO_PARSE,catalogFile,e.getMessage()),e);
   645             }
   646             return 2;
   647         }
   648         if( args[i].equals("-Xtest-class-name-allocator") ) {
   649             classNameAllocator = new ClassNameAllocator() {
   650                 public String assignClassName(String packageName, String className) {
   651                     System.out.printf("assignClassName(%s,%s)\n",packageName,className);
   652                     return className+"_Type";
   653                 }
   654             };
   655             return 1;
   656         }
   658         if (args[i].equals("-encoding")) {
   659             encoding = requireArgument("-encoding", args, ++i);
   660             try {
   661                 if (!Charset.isSupported(encoding)) {
   662                     throw new BadCommandLineException(
   663                         Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
   664                 }
   665             } catch (IllegalCharsetNameException icne) {
   666                 throw new BadCommandLineException(
   667                     Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
   668             }
   669             return 2;
   670         }
   672         // see if this is one of the extensions
   673         for( Plugin plugin : getAllPlugins() ) {
   674             try {
   675                 if( ('-'+plugin.getOptionName()).equals(args[i]) ) {
   676                     activePlugins.add(plugin);
   677                     plugin.onActivated(this);
   678                     pluginURIs.addAll(plugin.getCustomizationURIs());
   680                     // give the plugin a chance to parse arguments to this option.
   681                     // this is new in 2.1, and due to the backward compatibility reason,
   682                     // if plugin didn't understand it, we still return 1 to indicate
   683                     // that this option is consumed.
   684                     int r = plugin.parseArgument(this,args,i);
   685                     if(r!=0)
   686                         return r;
   687                     else
   688                         return 1;
   689                 }
   691                 int r = plugin.parseArgument(this,args,i);
   692                 if(r!=0)    return r;
   693             } catch (IOException e) {
   694                 throw new BadCommandLineException(e.getMessage(),e);
   695             }
   696         }
   698         return 0;   // unrecognized
   699     }
   701     private void parseProxy(String text) throws BadCommandLineException {
   702         int i = text.lastIndexOf('@');
   703         int j = text.lastIndexOf(':');
   705         if (i > 0) {
   706             proxyAuth = text.substring(0, i);
   707             if (j > i) {
   708                 proxyHost = text.substring(i + 1, j);
   709                 proxyPort = text.substring(j + 1);
   710             } else {
   711                 proxyHost = text.substring(i + 1);
   712                 proxyPort = "80";
   713             }
   714         } else {
   715             //no auth info
   716             if (j < 0) {
   717                 //no port
   718                 proxyHost = text;
   719                 proxyPort = "80";
   720             } else {
   721                 proxyHost = text.substring(0, j);
   722                 proxyPort = text.substring(j + 1);
   723             }
   724         }
   725         try {
   726             Integer.valueOf(proxyPort);
   727         } catch (NumberFormatException e) {
   728             throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY,text));
   729         }
   730     }
   732     /**
   733      * Obtains an operand and reports an error if it's not there.
   734      */
   735     public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException {
   736         if (i == args.length || args[i].startsWith("-")) {
   737             throw new BadCommandLineException(
   738                 Messages.format(Messages.MISSING_OPERAND,optionName));
   739         }
   740         return args[i];
   741     }
   743     /**
   744      * Parses a token to a file (or a set of files)
   745      * and add them as {@link InputSource} to the specified list.
   746      *
   747      * @param suffix
   748      *      If the given token is a directory name, we do a recusive search
   749      *      and find all files that have the given suffix.
   750      */
   751     private void addFile(String name, List<InputSource> target, String suffix) throws BadCommandLineException {
   752         Object src;
   753         try {
   754             src = Util.getFileOrURL(name);
   755         } catch (IOException e) {
   756             throw new BadCommandLineException(
   757                 Messages.format(Messages.NOT_A_FILE_NOR_URL,name));
   758         }
   759         if(src instanceof URL) {
   760             target.add(absolutize(new InputSource(Util.escapeSpace(((URL)src).toExternalForm()))));
   761         } else {
   762             File fsrc = (File)src;
   763             if(fsrc.isDirectory()) {
   764                 addRecursive(fsrc,suffix,target);
   765             } else {
   766                 target.add(absolutize(fileToInputSource(fsrc)));
   767             }
   768         }
   769     }
   771     /**
   772      * Adds a new catalog file.
   773      */
   774     public void addCatalog(File catalogFile) throws IOException {
   775         if(entityResolver==null) {
   776             CatalogManager.getStaticManager().setIgnoreMissingProperties(true);
   777             entityResolver = new CatalogResolver(true);
   778         }
   779         ((CatalogResolver)entityResolver).getCatalog().parseCatalog(catalogFile.getPath());
   780     }
   782     /**
   783      * Parses arguments and fill fields of this object.
   784      *
   785      * @exception BadCommandLineException
   786      *      thrown when there's a problem in the command-line arguments
   787      */
   788     public void parseArguments( String[] args ) throws BadCommandLineException {
   790         for (int i = 0; i < args.length; i++) {
   791             if(args[i].length()==0)
   792                 throw new BadCommandLineException();
   793             if (args[i].charAt(0) == '-') {
   794                 int j = parseArgument(args,i);
   795                 if(j==0)
   796                     throw new BadCommandLineException(
   797                         Messages.format(Messages.UNRECOGNIZED_PARAMETER, args[i]));
   798                 i += (j-1);
   799             } else {
   800                 if(args[i].endsWith(".jar"))
   801                     scanEpisodeFile(new File(args[i]));
   802                 else
   803                     addFile(args[i],grammars,".xsd");
   804             }
   805         }
   807         // configure proxy
   808         if (proxyHost != null || proxyPort != null) {
   809             if (proxyHost != null && proxyPort != null) {
   810                 System.setProperty("http.proxyHost", proxyHost);
   811                 System.setProperty("http.proxyPort", proxyPort);
   812                 System.setProperty("https.proxyHost", proxyHost);
   813                 System.setProperty("https.proxyPort", proxyPort);
   814             } else if (proxyHost == null) {
   815                 throw new BadCommandLineException(
   816                     Messages.format(Messages.MISSING_PROXYHOST));
   817             } else {
   818                 throw new BadCommandLineException(
   819                     Messages.format(Messages.MISSING_PROXYPORT));
   820             }
   821             if (proxyAuth != null) {
   822                 DefaultAuthenticator.getAuthenticator().setProxyAuth(proxyAuth);
   823             }
   824         }
   826         if (grammars.isEmpty())
   827             throw new BadCommandLineException(
   828                 Messages.format(Messages.MISSING_GRAMMAR));
   830         if( schemaLanguage==null )
   831             schemaLanguage = guessSchemaLanguage();
   833 //        if(target==SpecVersion.V2_2 && !isExtensionMode())
   834 //            throw new BadCommandLineException(
   835 //                "Currently 2.2 is still not finalized yet, so using it requires the -extension switch." +
   836 //                "NOTE THAT 2.2 SPEC MAY CHANGE BEFORE IT BECOMES FINAL.");
   838         if(pluginLoadFailure!=null)
   839             throw new BadCommandLineException(
   840                 Messages.format(Messages.PLUGIN_LOAD_FAILURE,pluginLoadFailure));
   841     }
   843     /**
   844      * Finds the <tt>META-INF/sun-jaxb.episode</tt> file to add as a binding customization.
   845      */
   846     public void scanEpisodeFile(File jar) throws BadCommandLineException {
   847         try {
   848             URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()});
   849             Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode");
   850             while (resources.hasMoreElements()) {
   851                 URL url = resources.nextElement();
   852                 addBindFile(new InputSource(url.toExternalForm()));
   853             }
   854         } catch (IOException e) {
   855             throw new BadCommandLineException(
   856                     Messages.format(Messages.FAILED_TO_LOAD,jar,e.getMessage()), e);
   857         }
   858     }
   861     /**
   862      * Guesses the schema language.
   863      */
   864     public Language guessSchemaLanguage() {
   866         // otherwise, use the file extension.
   867         // not a good solution, but very easy.
   868         if ((grammars != null) && (grammars.size() > 0)) {
   869             String name = grammars.get(0).getSystemId().toLowerCase();
   871             if (name.endsWith(".rng"))
   872                 return Language.RELAXNG;
   873             if (name.endsWith(".rnc"))
   874                 return Language.RELAXNG_COMPACT;
   875             if (name.endsWith(".dtd"))
   876                 return Language.DTD;
   877             if (name.endsWith(".wsdl"))
   878                 return Language.WSDL;
   879         }
   881         // by default, assume XML Schema
   882         return Language.XMLSCHEMA;
   883     }
   885     /**
   886      * Creates a configured CodeWriter that produces files into the specified directory.
   887      */
   888     public CodeWriter createCodeWriter() throws IOException {
   889         return createCodeWriter(new FileCodeWriter( targetDir, readOnly, encoding ));
   890     }
   892     /**
   893      * Creates a configured CodeWriter that produces files into the specified directory.
   894      */
   895     public CodeWriter createCodeWriter( CodeWriter core ) {
   896         if(noFileHeader)
   897             return core;
   899         return new PrologCodeWriter( core,getPrologComment() );
   900     }
   902     /**
   903      * Gets the string suitable to be used as the prolog comment baked into artifacts.
   904      * This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..."
   905      */
   906     public String getPrologComment() {
   907         // generate format syntax: <date> 'at' <time>
   908         String format =
   909             Messages.format(Messages.DATE_FORMAT)
   910                 + " '"
   911                 + Messages.format(Messages.AT)
   912                 + "' "
   913                 + Messages.format(Messages.TIME_FORMAT);
   914         SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.ENGLISH);
   916         return Messages.format(
   917             Messages.FILE_PROLOG_COMMENT,
   918             dateFormat.format(new Date()));
   919     }
   921     /**
   922      * If a plugin failed to load, report.
   923      */
   924     private static String pluginLoadFailure;
   926     /**
   927      * Looks for all "META-INF/services/[className]" files and
   928      * create one instance for each class name found inside this file.
   929      */
   930     private static <T> T[] findServices( Class<T> clazz, ClassLoader classLoader ) {
   931         // if true, print debug output
   932         final boolean debug = com.sun.tools.internal.xjc.util.Util.getSystemProperty(Options.class,"findServices")!=null;
   934         // if we are running on Mustang or Dolphin, use ServiceLoader
   935         // so that we can take advantage of JSR-277 module system.
   936         try {
   937             Class<?> serviceLoader = Class.forName("java.util.ServiceLoader");
   938             if(debug)
   939                 System.out.println("Using java.util.ServiceLoader");
   940             Iterable<T> itr = (Iterable<T>)serviceLoader.getMethod("load",Class.class,ClassLoader.class).invoke(null,clazz,classLoader);
   941             List<T> r = new ArrayList<T>();
   942             for (T t : itr)
   943                 r.add(t);
   944             return r.toArray((T[])Array.newInstance(clazz,r.size()));
   945         } catch (ClassNotFoundException e) {
   946             // fall through
   947         } catch (IllegalAccessException e) {
   948             Error x = new IllegalAccessError();
   949             x.initCause(e);
   950             throw x;
   951         } catch (InvocationTargetException e) {
   952             Throwable x = e.getTargetException();
   953             if (x instanceof RuntimeException)
   954                 throw (RuntimeException) x;
   955             if (x instanceof Error)
   956                 throw (Error) x;
   957             throw new Error(x);
   958         } catch (NoSuchMethodException e) {
   959             Error x = new NoSuchMethodError();
   960             x.initCause(e);
   961             throw x;
   962         }
   964         String serviceId = "META-INF/services/" + clazz.getName();
   966         // used to avoid creating the same instance twice
   967         Set<String> classNames = new HashSet<String>();
   969         if(debug) {
   970             System.out.println("Looking for "+serviceId+" for add-ons");
   971         }
   973         // try to find services in CLASSPATH
   974         try {
   975             Enumeration<URL> e = classLoader.getResources(serviceId);
   976             if(e==null) return (T[])Array.newInstance(clazz,0);
   978             ArrayList<T> a = new ArrayList<T>();
   979             while(e.hasMoreElements()) {
   980                 URL url = e.nextElement();
   981                 BufferedReader reader=null;
   983                 if(debug) {
   984                     System.out.println("Checking "+url+" for an add-on");
   985                 }
   987                 try {
   988                     reader = new BufferedReader(new InputStreamReader(url.openStream()));
   989                     String impl;
   990                     while((impl = reader.readLine())!=null ) {
   991                         // try to instanciate the object
   992                         impl = impl.trim();
   993                         if(classNames.add(impl)) {
   994                             Class implClass = classLoader.loadClass(impl);
   995                             if(!clazz.isAssignableFrom(implClass)) {
   996                                 pluginLoadFailure = impl+" is not a subclass of "+clazz+". Skipping";
   997                                 if(debug)
   998                                     System.out.println(pluginLoadFailure);
   999                                 continue;
  1001                             if(debug) {
  1002                                 System.out.println("Attempting to instanciate "+impl);
  1004                             a.add(clazz.cast(implClass.newInstance()));
  1007                     reader.close();
  1008                 } catch( Exception ex ) {
  1009                     // let it go.
  1010                     StringWriter w = new StringWriter();
  1011                     ex.printStackTrace(new PrintWriter(w));
  1012                     pluginLoadFailure = w.toString();
  1013                     if(debug) {
  1014                         System.out.println(pluginLoadFailure);
  1016                     if( reader!=null ) {
  1017                         try {
  1018                             reader.close();
  1019                         } catch( IOException ex2 ) {
  1020                             // ignore
  1026             return a.toArray((T[])Array.newInstance(clazz,a.size()));
  1027         } catch( Throwable e ) {
  1028             // ignore any error
  1029             StringWriter w = new StringWriter();
  1030             e.printStackTrace(new PrintWriter(w));
  1031             pluginLoadFailure = w.toString();
  1032             if(debug) {
  1033                 System.out.println(pluginLoadFailure);
  1035             return (T[])Array.newInstance(clazz,0);
  1039     // this is a convenient place to expose the build version to xjc plugins
  1040     public static String getBuildID() {
  1041         return Messages.format(Messages.BUILD_ID);
  1044     public static String normalizeSystemId(String systemId) {
  1045         try {
  1046             systemId = new URI(systemId).normalize().toString();
  1047         } catch (URISyntaxException e) {
  1048             // leave the system ID untouched. In my experience URI is often too strict
  1050         return systemId;

mercurial