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

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

     1 /*
     2  * Copyright (c) 1997, 2011, 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;
    48 import java.util.regex.Matcher;
    49 import java.util.regex.Pattern;
    51 import com.sun.codemodel.internal.CodeWriter;
    52 import com.sun.codemodel.internal.JPackage;
    53 import com.sun.codemodel.internal.writer.FileCodeWriter;
    54 import com.sun.codemodel.internal.writer.PrologCodeWriter;
    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      * Check the source schemas with extra scrutiny.
   110      * The exact meaning depends on the schema language.
   111      */
   112     public boolean strictCheck =true;
   114     /**
   115      * If -explicit-annotation option is specified.
   116      * <p>
   117      * This generates code that works around issues specific to 1.4 runtime.
   118      */
   119     public boolean runtime14 = false;
   121     /**
   122      * If true, try to resolve name conflicts automatically by assigning mechanical numbers.
   123      */
   124     public boolean automaticNameConflictResolution = false;
   126     /**
   127      * strictly follow the compatibility rules and reject schemas that
   128      * contain features from App. E.2, use vendor binding extensions
   129      */
   130     public static final int STRICT = 1;
   131     /**
   132      * loosely follow the compatibility rules and allow the use of vendor
   133      * binding extensions
   134      */
   135     public static final int EXTENSION = 2;
   137     /**
   138      * this switch determines how carefully the compiler will follow
   139      * the compatibility rules in the spec. Either <code>STRICT</code>
   140      * or <code>EXTENSION</code>.
   141      */
   142     public int compatibilityMode = STRICT;
   144     public boolean isExtensionMode() {
   145         return compatibilityMode==EXTENSION;
   146     }
   148     private static final Logger logger = com.sun.xml.internal.bind.Util.getClassLogger();
   150     /**
   151      * Generates output for the specified version of the runtime.
   152      */
   153     public SpecVersion target = SpecVersion.LATEST;
   155     private boolean is2_2 = true;
   157     public Options() {
   158         if (is2_2) {
   159             try {
   160                 Class.forName("javax.xml.bind.JAXBPermission");
   161             } catch (ClassNotFoundException cnfe) {
   162                 is2_2 = false;
   163             }
   164             if (!is2_2) {
   165                 target = SpecVersion.V2_1;
   166             } else {
   167                 target = SpecVersion.LATEST;
   168             }
   169         }
   170     }
   172     /**
   173      * Target directory when producing files.
   174      * <p>
   175      * This field is not used when XJC is driven through the XJC API.
   176      * Plugins that need to generate extra files should do so by using
   177      * {@link JPackage#addResourceFile(JResourceFile)}.
   178      */
   179     public File targetDir = new File(".");
   181     /**
   182      * Actually stores {@link CatalogResolver}, but the field
   183      * type is made to {@link EntityResolver} so that XJC can be
   184      * used even if resolver.jar is not available in the classpath.
   185      */
   186     public EntityResolver entityResolver = null;
   188     /**
   189      * Type of input schema language. One of the <code>SCHEMA_XXX</code>
   190      * constants.
   191      */
   192     private Language schemaLanguage = null;
   194     /**
   195      * The -p option that should control the default Java package that
   196      * will contain the generated code. Null if unspecified.
   197      */
   198     public String defaultPackage = null;
   200     /**
   201      * Similar to the -p option, but this one works with a lower priority,
   202      * and customizations overrides this. Used by JAX-RPC.
   203      */
   204     public String defaultPackage2 = null;
   206     /**
   207      * Input schema files as a list of {@link InputSource}s.
   208      */
   209     private final List<InputSource> grammars = new ArrayList<InputSource>();
   211     private final List<InputSource> bindFiles = new ArrayList<InputSource>();
   213     // Proxy setting.
   214     private String proxyHost = null;
   215     private String proxyPort = null;
   216     private String proxyUser = null;
   217     private String proxyPassword = 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 URLClassLoader getUserClassLoader( ClassLoader parent ) {
   463         return new URLClassLoader(
   464                 classpaths.toArray(new URL[classpaths.size()]),parent);
   465     }
   468     /**
   469      * Parses an option <code>args[i]</code> and return
   470      * the number of tokens consumed.
   471      *
   472      * @return
   473      *      0 if the argument is not understood. Returning 0
   474      *      will let the caller report an error.
   475      * @exception BadCommandLineException
   476      *      If the callee wants to provide a custom message for an error.
   477      */
   478     public int parseArgument( String[] args, int i ) throws BadCommandLineException {
   479         if (args[i].equals("-classpath") || args[i].equals("-cp")) {
   480             String a = requireArgument(args[i], args, ++i);
   481             for (String p : a.split(File.pathSeparator)) {
   482                 File file = new File(p);
   483                 try {
   484                     classpaths.add(file.toURL());
   485                 } catch (MalformedURLException e) {
   486                     throw new BadCommandLineException(
   487                         Messages.format(Messages.NOT_A_VALID_FILENAME,file),e);
   488                 }
   489             }
   490             return 2;
   491         }
   492         if (args[i].equals("-d")) {
   493             targetDir = new File(requireArgument("-d",args,++i));
   494             if( !targetDir.exists() )
   495                 throw new BadCommandLineException(
   496                     Messages.format(Messages.NON_EXISTENT_DIR,targetDir));
   497             return 2;
   498         }
   499         if (args[i].equals("-readOnly")) {
   500             readOnly = true;
   501             return 1;
   502         }
   503         if (args[i].equals("-p")) {
   504             defaultPackage = requireArgument("-p",args,++i);
   505             if(defaultPackage.length()==0) { // user specified default package
   506                 // there won't be any package to annotate, so disable them
   507                 // automatically as a usability feature
   508                 packageLevelAnnotations = false;
   509             }
   510             return 2;
   511         }
   512         if (args[i].equals("-debug")) {
   513             debugMode = true;
   514             verbose = true;
   515             return 1;
   516         }
   517         if (args[i].equals("-nv")) {
   518             strictCheck = false;
   519             return 1;
   520         }
   521         if( args[i].equals("-npa")) {
   522             packageLevelAnnotations = false;
   523             return 1;
   524         }
   525         if( args[i].equals("-no-header")) {
   526             noFileHeader = true;
   527             return 1;
   528         }
   529         if (args[i].equals("-verbose")) {
   530             verbose = true;
   531             return 1;
   532         }
   533         if (args[i].equals("-quiet")) {
   534             quiet = true;
   535             return 1;
   536         }
   537         if (args[i].equals("-XexplicitAnnotation")) {
   538             runtime14 = true;
   539             return 1;
   540         }
   541         if (args[i].equals("-enableIntrospection")) {
   542             enableIntrospection = true;
   543             return 1;
   544         }
   545         if (args[i].equals("-contentForWildcard")) {
   546             contentForWildcard = true;
   547             return 1;
   548         }
   549         if (args[i].equals("-XautoNameResolution")) {
   550             automaticNameConflictResolution = true;
   551             return 1;
   552         }
   553         if (args[i].equals("-b")) {
   554             addFile(requireArgument("-b",args,++i),bindFiles,".xjb");
   555             return 2;
   556         }
   557         if (args[i].equals("-dtd")) {
   558             schemaLanguage = Language.DTD;
   559             return 1;
   560         }
   561         if (args[i].equals("-relaxng")) {
   562             schemaLanguage = Language.RELAXNG;
   563             return 1;
   564         }
   565         if (args[i].equals("-relaxng-compact")) {
   566             schemaLanguage = Language.RELAXNG_COMPACT;
   567             return 1;
   568         }
   569         if (args[i].equals("-xmlschema")) {
   570             schemaLanguage = Language.XMLSCHEMA;
   571             return 1;
   572         }
   573         if (args[i].equals("-wsdl")) {
   574             schemaLanguage = Language.WSDL;
   575             return 1;
   576         }
   577         if (args[i].equals("-extension")) {
   578             compatibilityMode = EXTENSION;
   579             return 1;
   580         }
   581         if (args[i].equals("-target")) {
   582             String token = requireArgument("-target",args,++i);
   583             target = SpecVersion.parse(token);
   584             if(target==null)
   585                 throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_TARGET_VERSION,token));
   586             return 2;
   587         }
   588         if (args[i].equals("-httpproxyfile")) {
   589             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
   590                 throw new BadCommandLineException(
   591                     Messages.format(Messages.MISSING_PROXYFILE));
   592             }
   594             File file = new File(args[++i]);
   595             if(!file.exists()) {
   596                 throw new BadCommandLineException(
   597                     Messages.format(Messages.NO_SUCH_FILE,file));
   598             }
   600             try {
   601                 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
   602                 parseProxy(in.readLine());
   603                 in.close();
   604             } catch (IOException e) {
   605                 throw new BadCommandLineException(
   606                     Messages.format(Messages.FAILED_TO_PARSE,file,e.getMessage()),e);
   607             }
   609             return 2;
   610         }
   611         if (args[i].equals("-httpproxy")) {
   612             if (i == args.length - 1 || args[i + 1].startsWith("-")) {
   613                 throw new BadCommandLineException(
   614                     Messages.format(Messages.MISSING_PROXY));
   615             }
   617             parseProxy(args[++i]);
   618             return 2;
   619         }
   620         if (args[i].equals("-host")) {
   621             proxyHost = requireArgument("-host",args,++i);
   622             return 2;
   623         }
   624         if (args[i].equals("-port")) {
   625             proxyPort = requireArgument("-port",args,++i);
   626             return 2;
   627         }
   628         if( args[i].equals("-catalog") ) {
   629             // use Sun's "XML Entity and URI Resolvers" by Norman Walsh
   630             // to resolve external entities.
   631             // http://www.sun.com/xml/developers/resolver/
   633             File catalogFile = new File(requireArgument("-catalog",args,++i));
   634             try {
   635                 addCatalog(catalogFile);
   636             } catch (IOException e) {
   637                 throw new BadCommandLineException(
   638                     Messages.format(Messages.FAILED_TO_PARSE,catalogFile,e.getMessage()),e);
   639             }
   640             return 2;
   641         }
   642         if (args[i].equals("-source")) {
   643             String version = requireArgument("-source",args,++i);
   644             //For source 1.0 the 1.0 Driver is loaded
   645             //Hence anything other than 2.0 is defaulted to
   646             //2.0
   647             if( !version.equals("2.0") && !version.equals("2.1") )
   648                 throw new BadCommandLineException(
   649                     Messages.format(Messages.DEFAULT_VERSION));
   650             return 2;
   651         }
   652         if( args[i].equals("-Xtest-class-name-allocator") ) {
   653             classNameAllocator = new ClassNameAllocator() {
   654                 public String assignClassName(String packageName, String className) {
   655                     System.out.printf("assignClassName(%s,%s)\n",packageName,className);
   656                     return className+"_Type";
   657                 }
   658             };
   659             return 1;
   660         }
   662         if (args[i].equals("-encoding")) {
   663             encoding = requireArgument("-encoding", args, ++i);
   664             try {
   665                 if (!Charset.isSupported(encoding)) {
   666                     throw new BadCommandLineException(
   667                         Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
   668                 }
   669             } catch (IllegalCharsetNameException icne) {
   670                 throw new BadCommandLineException(
   671                     Messages.format(Messages.UNSUPPORTED_ENCODING, encoding));
   672             }
   673             return 2;
   674         }
   676         // see if this is one of the extensions
   677         for( Plugin plugin : getAllPlugins() ) {
   678             try {
   679                 if( ('-'+plugin.getOptionName()).equals(args[i]) ) {
   680                     activePlugins.add(plugin);
   681                     plugin.onActivated(this);
   682                     pluginURIs.addAll(plugin.getCustomizationURIs());
   684                     // give the plugin a chance to parse arguments to this option.
   685                     // this is new in 2.1, and due to the backward compatibility reason,
   686                     // if plugin didn't understand it, we still return 1 to indicate
   687                     // that this option is consumed.
   688                     int r = plugin.parseArgument(this,args,i);
   689                     if(r!=0)
   690                         return r;
   691                     else
   692                         return 1;
   693                 }
   695                 int r = plugin.parseArgument(this,args,i);
   696                 if(r!=0)    return r;
   697             } catch (IOException e) {
   698                 throw new BadCommandLineException(e.getMessage(),e);
   699             }
   700         }
   702         return 0;   // unrecognized
   703     }
   705     private void parseProxy(String text) throws BadCommandLineException {
   706         // syntax is [user[:password]@]proxyHost:proxyPort
   707         String token = "([^@:]+)";
   708         Pattern p = Pattern.compile("(?:"+token+"(?:\\:"+token+")?\\@)?"+token+"(?:\\:"+token+")");
   710         Matcher matcher = p.matcher(text);
   711         if(!matcher.matches())
   712             throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY,text));
   714         proxyUser = matcher.group(1);
   715         proxyPassword = matcher.group(2);
   716         proxyHost = matcher.group(3);
   717         proxyPort = matcher.group(4);
   718         try {
   719             Integer.valueOf(proxyPort);
   720         } catch (NumberFormatException e) {
   721             throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY,text));
   722         }
   723     }
   725     /**
   726      * Obtains an operand and reports an error if it's not there.
   727      */
   728     public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException {
   729         if (i == args.length || args[i].startsWith("-")) {
   730             throw new BadCommandLineException(
   731                 Messages.format(Messages.MISSING_OPERAND,optionName));
   732         }
   733         return args[i];
   734     }
   736     /**
   737      * Parses a token to a file (or a set of files)
   738      * and add them as {@link InputSource} to the specified list.
   739      *
   740      * @param suffix
   741      *      If the given token is a directory name, we do a recusive search
   742      *      and find all files that have the given suffix.
   743      */
   744     private void addFile(String name, List<InputSource> target, String suffix) throws BadCommandLineException {
   745         Object src;
   746         try {
   747             src = Util.getFileOrURL(name);
   748         } catch (IOException e) {
   749             throw new BadCommandLineException(
   750                 Messages.format(Messages.NOT_A_FILE_NOR_URL,name));
   751         }
   752         if(src instanceof URL) {
   753             target.add(absolutize(new InputSource(Util.escapeSpace(((URL)src).toExternalForm()))));
   754         } else {
   755             File fsrc = (File)src;
   756             if(fsrc.isDirectory()) {
   757                 addRecursive(fsrc,suffix,target);
   758             } else {
   759                 target.add(absolutize(fileToInputSource(fsrc)));
   760             }
   761         }
   762     }
   764     /**
   765      * Adds a new catalog file.
   766      */
   767     public void addCatalog(File catalogFile) throws IOException {
   768         if(entityResolver==null) {
   769             CatalogManager.getStaticManager().setIgnoreMissingProperties(true);
   770             entityResolver = new CatalogResolver(true);
   771         }
   772         ((CatalogResolver)entityResolver).getCatalog().parseCatalog(catalogFile.getPath());
   773     }
   775     /**
   776      * Parses arguments and fill fields of this object.
   777      *
   778      * @exception BadCommandLineException
   779      *      thrown when there's a problem in the command-line arguments
   780      */
   781     public void parseArguments( String[] args ) throws BadCommandLineException {
   783         for (int i = 0; i < args.length; i++) {
   784             if(args[i].length()==0)
   785                 throw new BadCommandLineException();
   786             if (args[i].charAt(0) == '-') {
   787                 int j = parseArgument(args,i);
   788                 if(j==0)
   789                     throw new BadCommandLineException(
   790                         Messages.format(Messages.UNRECOGNIZED_PARAMETER, args[i]));
   791                 i += (j-1);
   792             } else {
   793                 if(args[i].endsWith(".jar"))
   794                     scanEpisodeFile(new File(args[i]));
   795                 else
   796                     addFile(args[i],grammars,".xsd");
   797             }
   798         }
   800         // configure proxy
   801         if (proxyHost != null || proxyPort != null) {
   802             if (proxyHost != null && proxyPort != null) {
   803                 System.setProperty("http.proxyHost", proxyHost);
   804                 System.setProperty("http.proxyPort", proxyPort);
   805                 System.setProperty("https.proxyHost", proxyHost);
   806                 System.setProperty("https.proxyPort", proxyPort);
   807             } else if (proxyHost == null) {
   808                 throw new BadCommandLineException(
   809                     Messages.format(Messages.MISSING_PROXYHOST));
   810             } else {
   811                 throw new BadCommandLineException(
   812                     Messages.format(Messages.MISSING_PROXYPORT));
   813             }
   814             if(proxyUser!=null)
   815                 System.setProperty("http.proxyUser", proxyUser);
   816             if(proxyPassword!=null)
   817                 System.setProperty("http.proxyPassword", proxyPassword);
   819         }
   821         if (grammars.isEmpty())
   822             throw new BadCommandLineException(
   823                 Messages.format(Messages.MISSING_GRAMMAR));
   825         if( schemaLanguage==null )
   826             schemaLanguage = guessSchemaLanguage();
   828 //        if(target==SpecVersion.V2_2 && !isExtensionMode())
   829 //            throw new BadCommandLineException(
   830 //                "Currently 2.2 is still not finalized yet, so using it requires the -extension switch." +
   831 //                "NOTE THAT 2.2 SPEC MAY CHANGE BEFORE IT BECOMES FINAL.");
   833         if(pluginLoadFailure!=null)
   834             throw new BadCommandLineException(
   835                 Messages.format(Messages.PLUGIN_LOAD_FAILURE,pluginLoadFailure));
   836     }
   838     /**
   839      * Finds the <tt>META-INF/sun-jaxb.episode</tt> file to add as a binding customization.
   840      */
   841     public void scanEpisodeFile(File jar) throws BadCommandLineException {
   842         try {
   843             URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()});
   844             Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode");
   845             while (resources.hasMoreElements()) {
   846                 URL url = resources.nextElement();
   847                 addBindFile(new InputSource(url.toExternalForm()));
   848             }
   849         } catch (IOException e) {
   850             throw new BadCommandLineException(
   851                     Messages.format(Messages.FAILED_TO_LOAD,jar,e.getMessage()), e);
   852         }
   853     }
   856     /**
   857      * Guesses the schema language.
   858      */
   859     public Language guessSchemaLanguage() {
   861         // otherwise, use the file extension.
   862         // not a good solution, but very easy.
   863         if ((grammars != null) && (grammars.size() > 0)) {
   864             String name = grammars.get(0).getSystemId().toLowerCase();
   866             if (name.endsWith(".rng"))
   867                 return Language.RELAXNG;
   868             if (name.endsWith(".rnc"))
   869                 return Language.RELAXNG_COMPACT;
   870             if (name.endsWith(".dtd"))
   871                 return Language.DTD;
   872             if (name.endsWith(".wsdl"))
   873                 return Language.WSDL;
   874         }
   876         // by default, assume XML Schema
   877         return Language.XMLSCHEMA;
   878     }
   880     /**
   881      * Creates a configured CodeWriter that produces files into the specified directory.
   882      */
   883     public CodeWriter createCodeWriter() throws IOException {
   884         return createCodeWriter(new FileCodeWriter( targetDir, readOnly, encoding ));
   885     }
   887     /**
   888      * Creates a configured CodeWriter that produces files into the specified directory.
   889      */
   890     public CodeWriter createCodeWriter( CodeWriter core ) {
   891         if(noFileHeader)
   892             return core;
   894         return new PrologCodeWriter( core,getPrologComment() );
   895     }
   897     /**
   898      * Gets the string suitable to be used as the prolog comment baked into artifacts.
   899      * This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..."
   900      */
   901     public String getPrologComment() {
   902         // generate format syntax: <date> 'at' <time>
   903         String format =
   904             Messages.format(Messages.DATE_FORMAT)
   905                 + " '"
   906                 + Messages.format(Messages.AT)
   907                 + "' "
   908                 + Messages.format(Messages.TIME_FORMAT);
   909         SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.ENGLISH);
   911         return Messages.format(
   912             Messages.FILE_PROLOG_COMMENT,
   913             dateFormat.format(new Date()));
   914     }
   916     /**
   917      * If a plugin failed to load, report.
   918      */
   919     private static String pluginLoadFailure;
   921     /**
   922      * Looks for all "META-INF/services/[className]" files and
   923      * create one instance for each class name found inside this file.
   924      */
   925     private static <T> T[] findServices( Class<T> clazz, ClassLoader classLoader ) {
   926         // if true, print debug output
   927         final boolean debug = com.sun.tools.internal.xjc.util.Util.getSystemProperty(Options.class,"findServices")!=null;
   929         // if we are running on Mustang or Dolphin, use ServiceLoader
   930         // so that we can take advantage of JSR-277 module system.
   931         try {
   932             Class<?> serviceLoader = Class.forName("java.util.ServiceLoader");
   933             if(debug)
   934                 System.out.println("Using java.util.ServiceLoader");
   935             Iterable<T> itr = (Iterable<T>)serviceLoader.getMethod("load",Class.class,ClassLoader.class).invoke(null,clazz,classLoader);
   936             List<T> r = new ArrayList<T>();
   937             for (T t : itr)
   938                 r.add(t);
   939             return r.toArray((T[])Array.newInstance(clazz,r.size()));
   940         } catch (ClassNotFoundException e) {
   941             // fall through
   942         } catch (IllegalAccessException e) {
   943             Error x = new IllegalAccessError();
   944             x.initCause(e);
   945             throw x;
   946         } catch (InvocationTargetException e) {
   947             Throwable x = e.getTargetException();
   948             if (x instanceof RuntimeException)
   949                 throw (RuntimeException) x;
   950             if (x instanceof Error)
   951                 throw (Error) x;
   952             throw new Error(x);
   953         } catch (NoSuchMethodException e) {
   954             Error x = new NoSuchMethodError();
   955             x.initCause(e);
   956             throw x;
   957         }
   959         String serviceId = "META-INF/services/" + clazz.getName();
   961         // used to avoid creating the same instance twice
   962         Set<String> classNames = new HashSet<String>();
   964         if(debug) {
   965             System.out.println("Looking for "+serviceId+" for add-ons");
   966         }
   968         // try to find services in CLASSPATH
   969         try {
   970             Enumeration<URL> e = classLoader.getResources(serviceId);
   971             if(e==null) return (T[])Array.newInstance(clazz,0);
   973             ArrayList<T> a = new ArrayList<T>();
   974             while(e.hasMoreElements()) {
   975                 URL url = e.nextElement();
   976                 BufferedReader reader=null;
   978                 if(debug) {
   979                     System.out.println("Checking "+url+" for an add-on");
   980                 }
   982                 try {
   983                     reader = new BufferedReader(new InputStreamReader(url.openStream()));
   984                     String impl;
   985                     while((impl = reader.readLine())!=null ) {
   986                         // try to instanciate the object
   987                         impl = impl.trim();
   988                         if(classNames.add(impl)) {
   989                             Class implClass = classLoader.loadClass(impl);
   990                             if(!clazz.isAssignableFrom(implClass)) {
   991                                 pluginLoadFailure = impl+" is not a subclass of "+clazz+". Skipping";
   992                                 if(debug)
   993                                     System.out.println(pluginLoadFailure);
   994                                 continue;
   995                             }
   996                             if(debug) {
   997                                 System.out.println("Attempting to instanciate "+impl);
   998                             }
   999                             a.add(clazz.cast(implClass.newInstance()));
  1002                     reader.close();
  1003                 } catch( Exception ex ) {
  1004                     // let it go.
  1005                     StringWriter w = new StringWriter();
  1006                     ex.printStackTrace(new PrintWriter(w));
  1007                     pluginLoadFailure = w.toString();
  1008                     if(debug) {
  1009                         System.out.println(pluginLoadFailure);
  1011                     if( reader!=null ) {
  1012                         try {
  1013                             reader.close();
  1014                         } catch( IOException ex2 ) {
  1015                             // ignore
  1021             return a.toArray((T[])Array.newInstance(clazz,a.size()));
  1022         } catch( Throwable e ) {
  1023             // ignore any error
  1024             StringWriter w = new StringWriter();
  1025             e.printStackTrace(new PrintWriter(w));
  1026             pluginLoadFailure = w.toString();
  1027             if(debug) {
  1028                 System.out.println(pluginLoadFailure);
  1030             return (T[])Array.newInstance(clazz,0);
  1034     // this is a convenient place to expose the build version to xjc plugins
  1035     public static String getBuildID() {
  1036         return Messages.format(Messages.BUILD_ID);
  1039     public static String normalizeSystemId(String systemId) {
  1040         try {
  1041             systemId = new URI(systemId).normalize().toString();
  1042         } catch (URISyntaxException e) {
  1043             // leave the system ID untouched. In my experience URI is often too strict
  1045         return systemId;

mercurial