ohair@286: /* ohair@286: * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.tools.internal.xjc; ohair@286: ohair@286: import java.io.BufferedReader; ohair@286: import java.io.File; ohair@286: import java.io.FileInputStream; ohair@286: import java.io.IOException; ohair@286: import java.io.InputStreamReader; ohair@286: import java.io.PrintWriter; ohair@286: import java.io.StringWriter; ohair@286: import java.lang.reflect.Array; ohair@286: import java.lang.reflect.InvocationTargetException; ohair@286: import java.net.MalformedURLException; ohair@286: import java.net.URL; ohair@286: import java.net.URLClassLoader; ohair@286: import java.text.SimpleDateFormat; ohair@286: import java.util.ArrayList; ohair@286: import java.util.Arrays; ohair@286: import java.util.Date; ohair@286: import java.util.Enumeration; ohair@286: import java.util.HashSet; ohair@286: import java.util.List; ohair@286: import java.util.Set; ohair@286: import java.util.regex.Matcher; ohair@286: import java.util.regex.Pattern; ohair@286: ohair@286: import com.sun.codemodel.internal.CodeWriter; ohair@286: import com.sun.codemodel.internal.JPackage; ohair@286: import com.sun.codemodel.internal.writer.FileCodeWriter; ohair@286: import com.sun.codemodel.internal.writer.PrologCodeWriter; ohair@286: import com.sun.org.apache.xml.internal.resolver.CatalogManager; ohair@286: import com.sun.org.apache.xml.internal.resolver.tools.CatalogResolver; ohair@286: import com.sun.tools.internal.xjc.api.ClassNameAllocator; ohair@286: import com.sun.tools.internal.xjc.api.SpecVersion; ohair@286: import com.sun.tools.internal.xjc.generator.bean.field.FieldRendererFactory; ohair@286: import com.sun.tools.internal.xjc.model.Model; ohair@286: import com.sun.tools.internal.xjc.reader.Util; ohair@286: import com.sun.xml.internal.bind.api.impl.NameConverter; ohair@286: import java.net.URI; ohair@286: import java.net.URISyntaxException; ohair@286: import java.nio.charset.Charset; ohair@286: import java.nio.charset.IllegalCharsetNameException; ohair@286: import java.util.Locale; ohair@286: import java.util.logging.Level; ohair@286: import java.util.logging.Logger; ohair@286: ohair@286: import org.xml.sax.EntityResolver; ohair@286: import org.xml.sax.InputSource; ohair@286: ohair@286: /** ohair@286: * Global options. ohair@286: * ohair@286: *

ohair@286: * This class stores invocation configuration for XJC. ohair@286: * The configuration in this class should be abstract enough so that ohair@286: * it could be parsed from both command-line or Ant. ohair@286: */ ohair@286: public class Options ohair@286: { ohair@286: /** If "-debug" is specified. */ ohair@286: public boolean debugMode; ohair@286: ohair@286: /** If the "-verbose" option is specified. */ ohair@286: public boolean verbose; ohair@286: ohair@286: /** If the "-quiet" option is specified. */ ohair@286: public boolean quiet; ohair@286: ohair@286: /** If the -readOnly option is specified. */ ohair@286: public boolean readOnly; ohair@286: ohair@286: /** No file header comment (to be more friendly with diff.) */ ohair@286: public boolean noFileHeader; ohair@286: ohair@286: /** When on, fixes getter/setter generation to match the Bean Introspection API */ ohair@286: public boolean enableIntrospection; ohair@286: ohair@286: /** When on, generates content property for types with multiple xs:any derived elements (which is supposed to be correct behaviour) */ ohair@286: public boolean contentForWildcard; ohair@286: ohair@286: /** Encoding to be used by generated java sources, null for platform default. */ ohair@286: public String encoding; ohair@286: ohair@286: /** ohair@286: * Check the source schemas with extra scrutiny. ohair@286: * The exact meaning depends on the schema language. ohair@286: */ ohair@286: public boolean strictCheck =true; ohair@286: ohair@286: /** ohair@286: * If -explicit-annotation option is specified. ohair@286: *

ohair@286: * This generates code that works around issues specific to 1.4 runtime. ohair@286: */ ohair@286: public boolean runtime14 = false; ohair@286: ohair@286: /** ohair@286: * If true, try to resolve name conflicts automatically by assigning mechanical numbers. ohair@286: */ ohair@286: public boolean automaticNameConflictResolution = false; ohair@286: ohair@286: /** ohair@286: * strictly follow the compatibility rules and reject schemas that ohair@286: * contain features from App. E.2, use vendor binding extensions ohair@286: */ ohair@286: public static final int STRICT = 1; ohair@286: /** ohair@286: * loosely follow the compatibility rules and allow the use of vendor ohair@286: * binding extensions ohair@286: */ ohair@286: public static final int EXTENSION = 2; ohair@286: ohair@286: /** ohair@286: * this switch determines how carefully the compiler will follow ohair@286: * the compatibility rules in the spec. Either STRICT ohair@286: * or EXTENSION. ohair@286: */ ohair@286: public int compatibilityMode = STRICT; ohair@286: ohair@286: public boolean isExtensionMode() { ohair@286: return compatibilityMode==EXTENSION; ohair@286: } ohair@286: ohair@286: private static final Logger logger = com.sun.xml.internal.bind.Util.getClassLogger(); ohair@286: ohair@286: /** ohair@286: * Generates output for the specified version of the runtime. ohair@286: */ ohair@286: public SpecVersion target = SpecVersion.LATEST; ohair@286: ohair@286: private boolean is2_2 = true; ohair@286: ohair@286: public Options() { ohair@286: if (is2_2) { ohair@286: try { ohair@286: Class.forName("javax.xml.bind.JAXBPermission"); ohair@286: } catch (ClassNotFoundException cnfe) { ohair@286: is2_2 = false; ohair@286: } ohair@286: if (!is2_2) { ohair@286: target = SpecVersion.V2_1; ohair@286: } else { ohair@286: target = SpecVersion.LATEST; ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Target directory when producing files. ohair@286: *

ohair@286: * This field is not used when XJC is driven through the XJC API. ohair@286: * Plugins that need to generate extra files should do so by using ohair@286: * {@link JPackage#addResourceFile(JResourceFile)}. ohair@286: */ ohair@286: public File targetDir = new File("."); ohair@286: ohair@286: /** ohair@286: * Actually stores {@link CatalogResolver}, but the field ohair@286: * type is made to {@link EntityResolver} so that XJC can be ohair@286: * used even if resolver.jar is not available in the classpath. ohair@286: */ ohair@286: public EntityResolver entityResolver = null; ohair@286: ohair@286: /** ohair@286: * Type of input schema language. One of the SCHEMA_XXX ohair@286: * constants. ohair@286: */ ohair@286: private Language schemaLanguage = null; ohair@286: ohair@286: /** ohair@286: * The -p option that should control the default Java package that ohair@286: * will contain the generated code. Null if unspecified. ohair@286: */ ohair@286: public String defaultPackage = null; ohair@286: ohair@286: /** ohair@286: * Similar to the -p option, but this one works with a lower priority, ohair@286: * and customizations overrides this. Used by JAX-RPC. ohair@286: */ ohair@286: public String defaultPackage2 = null; ohair@286: ohair@286: /** ohair@286: * Input schema files as a list of {@link InputSource}s. ohair@286: */ ohair@286: private final List grammars = new ArrayList(); ohair@286: ohair@286: private final List bindFiles = new ArrayList(); ohair@286: ohair@286: // Proxy setting. ohair@286: private String proxyHost = null; ohair@286: private String proxyPort = null; ohair@286: private String proxyUser = null; ohair@286: private String proxyPassword = null; ohair@286: ohair@286: /** ohair@286: * {@link Plugin}s that are enabled in this compilation. ohair@286: */ ohair@286: public final List activePlugins = new ArrayList(); ohair@286: ohair@286: /** ohair@286: * All discovered {@link Plugin}s. ohair@286: * This is lazily parsed, so that we can take '-cp' option into account. ohair@286: * ohair@286: * @see #getAllPlugins() ohair@286: */ ohair@286: private List allPlugins; ohair@286: ohair@286: /** ohair@286: * Set of URIs that plug-ins recognize as extension bindings. ohair@286: */ ohair@286: public final Set pluginURIs = new HashSet(); ohair@286: ohair@286: /** ohair@286: * This allocator has the final say on deciding the class name. ohair@286: */ ohair@286: public ClassNameAllocator classNameAllocator; ohair@286: ohair@286: /** ohair@286: * This switch controls whether or not xjc will generate package level annotations ohair@286: */ ohair@286: public boolean packageLevelAnnotations = true; ohair@286: ohair@286: /** ohair@286: * This {@link FieldRendererFactory} determines how the fields are generated. ohair@286: */ ohair@286: private FieldRendererFactory fieldRendererFactory = new FieldRendererFactory(); ohair@286: /** ohair@286: * Used to detect if two {@link Plugin}s try to overwrite {@link #fieldRendererFactory}. ohair@286: */ ohair@286: private Plugin fieldRendererFactoryOwner = null; ohair@286: ohair@286: /** ohair@286: * If this is non-null, we use this {@link NameConverter} over the one ohair@286: * given in the schema/binding. ohair@286: */ ohair@286: private NameConverter nameConverter = null; ohair@286: /** ohair@286: * Used to detect if two {@link Plugin}s try to overwrite {@link #nameConverter}. ohair@286: */ ohair@286: private Plugin nameConverterOwner = null; ohair@286: ohair@286: /** ohair@286: * Gets the active {@link FieldRendererFactory} that shall be used to build {@link Model}. ohair@286: * ohair@286: * @return always non-null. ohair@286: */ ohair@286: public FieldRendererFactory getFieldRendererFactory() { ohair@286: return fieldRendererFactory; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Sets the {@link FieldRendererFactory}. ohair@286: * ohair@286: *

ohair@286: * This method is for plugins to call to set a custom {@link FieldRendererFactory}. ohair@286: * ohair@286: * @param frf ohair@286: * The {@link FieldRendererFactory} to be installed. Must not be null. ohair@286: * @param owner ohair@286: * Identifies the plugin that owns this {@link FieldRendererFactory}. ohair@286: * When two {@link Plugin}s try to call this method, this allows XJC ohair@286: * to report it as a user-friendly error message. ohair@286: * ohair@286: * @throws BadCommandLineException ohair@286: * If a conflit happens, this exception carries a user-friendly error ohair@286: * message, indicating a conflict. ohair@286: */ ohair@286: public void setFieldRendererFactory(FieldRendererFactory frf, Plugin owner) throws BadCommandLineException { ohair@286: // since this method is for plugins, make it bit more fool-proof than usual ohair@286: if(frf==null) ohair@286: throw new IllegalArgumentException(); ohair@286: if(fieldRendererFactoryOwner!=null) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.FIELD_RENDERER_CONFLICT, ohair@286: fieldRendererFactoryOwner.getOptionName(), ohair@286: owner.getOptionName() )); ohair@286: } ohair@286: this.fieldRendererFactoryOwner = owner; ohair@286: this.fieldRendererFactory = frf; ohair@286: } ohair@286: ohair@286: ohair@286: /** ohair@286: * Gets the active {@link NameConverter} that shall be used to build {@link Model}. ohair@286: * ohair@286: * @return can be null, in which case it's up to the binding. ohair@286: */ ohair@286: public NameConverter getNameConverter() { ohair@286: return nameConverter; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Sets the {@link NameConverter}. ohair@286: * ohair@286: *

ohair@286: * This method is for plugins to call to set a custom {@link NameConverter}. ohair@286: * ohair@286: * @param nc ohair@286: * The {@link NameConverter} to be installed. Must not be null. ohair@286: * @param owner ohair@286: * Identifies the plugin that owns this {@link NameConverter}. ohair@286: * When two {@link Plugin}s try to call this method, this allows XJC ohair@286: * to report it as a user-friendly error message. ohair@286: * ohair@286: * @throws BadCommandLineException ohair@286: * If a conflit happens, this exception carries a user-friendly error ohair@286: * message, indicating a conflict. ohair@286: */ ohair@286: public void setNameConverter(NameConverter nc, Plugin owner) throws BadCommandLineException { ohair@286: // since this method is for plugins, make it bit more fool-proof than usual ohair@286: if(nc==null) ohair@286: throw new IllegalArgumentException(); ohair@286: if(nameConverter!=null) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.NAME_CONVERTER_CONFLICT, ohair@286: nameConverterOwner.getOptionName(), ohair@286: owner.getOptionName() )); ohair@286: } ohair@286: this.nameConverterOwner = owner; ohair@286: this.nameConverter = nc; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets all the {@link Plugin}s discovered so far. ohair@286: * ohair@286: *

ohair@286: * A plugins are enumerated when this method is called for the first time, ohair@286: * by taking {@link #classpaths} into account. That means ohair@286: * "-cp plugin.jar" has to come before you specify options to enable it. ohair@286: */ ohair@286: public List getAllPlugins() { ohair@286: if(allPlugins==null) { ohair@286: allPlugins = new ArrayList(); ohair@286: ClassLoader ucl = getUserClassLoader(SecureLoader.getClassClassLoader(getClass())); ohair@286: allPlugins.addAll(Arrays.asList(findServices(Plugin.class,ucl))); ohair@286: } ohair@286: ohair@286: return allPlugins; ohair@286: } ohair@286: ohair@286: public Language getSchemaLanguage() { ohair@286: if( schemaLanguage==null) ohair@286: schemaLanguage = guessSchemaLanguage(); ohair@286: return schemaLanguage; ohair@286: } ohair@286: public void setSchemaLanguage(Language _schemaLanguage) { ohair@286: this.schemaLanguage = _schemaLanguage; ohair@286: } ohair@286: ohair@286: /** Input schema files. */ ohair@286: public InputSource[] getGrammars() { ohair@286: return grammars.toArray(new InputSource[grammars.size()]); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Adds a new input schema. ohair@286: */ ohair@286: public void addGrammar( InputSource is ) { ohair@286: grammars.add(absolutize(is)); ohair@286: } ohair@286: ohair@286: private InputSource fileToInputSource( File source ) { ohair@286: try { ohair@286: String url = source.toURL().toExternalForm(); ohair@286: return new InputSource(Util.escapeSpace(url)); ohair@286: } catch (MalformedURLException e) { ohair@286: return new InputSource(source.getPath()); ohair@286: } ohair@286: } ohair@286: ohair@286: public void addGrammar( File source ) { ohair@286: addGrammar(fileToInputSource(source)); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Recursively scan directories and add all XSD files in it. ohair@286: */ ohair@286: public void addGrammarRecursive( File dir ) { ohair@286: addRecursive(dir,".xsd",grammars); ohair@286: } ohair@286: ohair@286: private void addRecursive( File dir, String suffix, List result ) { ohair@286: File[] files = dir.listFiles(); ohair@286: if(files==null) return; // work defensively ohair@286: ohair@286: for( File f : files ) { ohair@286: if(f.isDirectory()) ohair@286: addRecursive(f,suffix,result); ohair@286: else ohair@286: if(f.getPath().endsWith(suffix)) ohair@286: result.add(absolutize(fileToInputSource(f))); ohair@286: } ohair@286: } ohair@286: ohair@286: ohair@286: private InputSource absolutize(InputSource is) { ohair@286: // absolutize all the system IDs in the input, so that we can map system IDs to DOM trees. ohair@286: try { ohair@286: URL baseURL = new File(".").getCanonicalFile().toURL(); ohair@286: is.setSystemId( new URL(baseURL,is.getSystemId()).toExternalForm() ); ohair@286: } catch( IOException e ) { ohair@286: logger.log(Level.FINE, "{0}, {1}", new Object[]{is.getSystemId(), e.getLocalizedMessage()}); ohair@286: } ohair@286: return is; ohair@286: } ohair@286: ohair@286: /** Input external binding files. */ ohair@286: public InputSource[] getBindFiles() { ohair@286: return bindFiles.toArray(new InputSource[bindFiles.size()]); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Adds a new binding file. ohair@286: */ ohair@286: public void addBindFile( InputSource is ) { ohair@286: bindFiles.add(absolutize(is)); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Adds a new binding file. ohair@286: */ ohair@286: public void addBindFile( File bindFile ) { ohair@286: bindFiles.add(fileToInputSource(bindFile)); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Recursively scan directories and add all ".xjb" files in it. ohair@286: */ ohair@286: public void addBindFileRecursive( File dir ) { ohair@286: addRecursive(dir,".xjb",bindFiles); ohair@286: } ohair@286: ohair@286: public final List classpaths = new ArrayList(); ohair@286: /** ohair@286: * Gets a classLoader that can load classes specified via the ohair@286: * -classpath option. ohair@286: */ ohair@286: public URLClassLoader getUserClassLoader( ClassLoader parent ) { ohair@286: return new URLClassLoader( ohair@286: classpaths.toArray(new URL[classpaths.size()]),parent); ohair@286: } ohair@286: ohair@286: ohair@286: /** ohair@286: * Parses an option args[i] and return ohair@286: * the number of tokens consumed. ohair@286: * ohair@286: * @return ohair@286: * 0 if the argument is not understood. Returning 0 ohair@286: * will let the caller report an error. ohair@286: * @exception BadCommandLineException ohair@286: * If the callee wants to provide a custom message for an error. ohair@286: */ ohair@286: public int parseArgument( String[] args, int i ) throws BadCommandLineException { ohair@286: if (args[i].equals("-classpath") || args[i].equals("-cp")) { ohair@286: String a = requireArgument(args[i], args, ++i); ohair@286: for (String p : a.split(File.pathSeparator)) { ohair@286: File file = new File(p); ohair@286: try { ohair@286: classpaths.add(file.toURL()); ohair@286: } catch (MalformedURLException e) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.NOT_A_VALID_FILENAME,file),e); ohair@286: } ohair@286: } ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-d")) { ohair@286: targetDir = new File(requireArgument("-d",args,++i)); ohair@286: if( !targetDir.exists() ) ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.NON_EXISTENT_DIR,targetDir)); ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-readOnly")) { ohair@286: readOnly = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-p")) { ohair@286: defaultPackage = requireArgument("-p",args,++i); ohair@286: if(defaultPackage.length()==0) { // user specified default package ohair@286: // there won't be any package to annotate, so disable them ohair@286: // automatically as a usability feature ohair@286: packageLevelAnnotations = false; ohair@286: } ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-debug")) { ohair@286: debugMode = true; ohair@286: verbose = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-nv")) { ohair@286: strictCheck = false; ohair@286: return 1; ohair@286: } ohair@286: if( args[i].equals("-npa")) { ohair@286: packageLevelAnnotations = false; ohair@286: return 1; ohair@286: } ohair@286: if( args[i].equals("-no-header")) { ohair@286: noFileHeader = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-verbose")) { ohair@286: verbose = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-quiet")) { ohair@286: quiet = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-XexplicitAnnotation")) { ohair@286: runtime14 = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-enableIntrospection")) { ohair@286: enableIntrospection = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-contentForWildcard")) { ohair@286: contentForWildcard = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-XautoNameResolution")) { ohair@286: automaticNameConflictResolution = true; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-b")) { ohair@286: addFile(requireArgument("-b",args,++i),bindFiles,".xjb"); ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-dtd")) { ohair@286: schemaLanguage = Language.DTD; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-relaxng")) { ohair@286: schemaLanguage = Language.RELAXNG; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-relaxng-compact")) { ohair@286: schemaLanguage = Language.RELAXNG_COMPACT; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-xmlschema")) { ohair@286: schemaLanguage = Language.XMLSCHEMA; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-wsdl")) { ohair@286: schemaLanguage = Language.WSDL; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-extension")) { ohair@286: compatibilityMode = EXTENSION; ohair@286: return 1; ohair@286: } ohair@286: if (args[i].equals("-target")) { ohair@286: String token = requireArgument("-target",args,++i); ohair@286: target = SpecVersion.parse(token); ohair@286: if(target==null) ohair@286: throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_TARGET_VERSION,token)); ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-httpproxyfile")) { ohair@286: if (i == args.length - 1 || args[i + 1].startsWith("-")) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.MISSING_PROXYFILE)); ohair@286: } ohair@286: ohair@286: File file = new File(args[++i]); ohair@286: if(!file.exists()) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.NO_SUCH_FILE,file)); ohair@286: } ohair@286: ohair@286: try { ohair@286: BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8")); ohair@286: parseProxy(in.readLine()); ohair@286: in.close(); ohair@286: } catch (IOException e) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.FAILED_TO_PARSE,file,e.getMessage()),e); ohair@286: } ohair@286: ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-httpproxy")) { ohair@286: if (i == args.length - 1 || args[i + 1].startsWith("-")) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.MISSING_PROXY)); ohair@286: } ohair@286: ohair@286: parseProxy(args[++i]); ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-host")) { ohair@286: proxyHost = requireArgument("-host",args,++i); ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-port")) { ohair@286: proxyPort = requireArgument("-port",args,++i); ohair@286: return 2; ohair@286: } ohair@286: if( args[i].equals("-catalog") ) { ohair@286: // use Sun's "XML Entity and URI Resolvers" by Norman Walsh ohair@286: // to resolve external entities. ohair@286: // http://www.sun.com/xml/developers/resolver/ ohair@286: ohair@286: File catalogFile = new File(requireArgument("-catalog",args,++i)); ohair@286: try { ohair@286: addCatalog(catalogFile); ohair@286: } catch (IOException e) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.FAILED_TO_PARSE,catalogFile,e.getMessage()),e); ohair@286: } ohair@286: return 2; ohair@286: } ohair@286: if (args[i].equals("-source")) { ohair@286: String version = requireArgument("-source",args,++i); ohair@286: //For source 1.0 the 1.0 Driver is loaded ohair@286: //Hence anything other than 2.0 is defaulted to ohair@286: //2.0 ohair@286: if( !version.equals("2.0") && !version.equals("2.1") ) ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.DEFAULT_VERSION)); ohair@286: return 2; ohair@286: } ohair@286: if( args[i].equals("-Xtest-class-name-allocator") ) { ohair@286: classNameAllocator = new ClassNameAllocator() { ohair@286: public String assignClassName(String packageName, String className) { ohair@286: System.out.printf("assignClassName(%s,%s)\n",packageName,className); ohair@286: return className+"_Type"; ohair@286: } ohair@286: }; ohair@286: return 1; ohair@286: } ohair@286: ohair@286: if (args[i].equals("-encoding")) { ohair@286: encoding = requireArgument("-encoding", args, ++i); ohair@286: try { ohair@286: if (!Charset.isSupported(encoding)) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.UNSUPPORTED_ENCODING, encoding)); ohair@286: } ohair@286: } catch (IllegalCharsetNameException icne) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.UNSUPPORTED_ENCODING, encoding)); ohair@286: } ohair@286: return 2; ohair@286: } ohair@286: ohair@286: // see if this is one of the extensions ohair@286: for( Plugin plugin : getAllPlugins() ) { ohair@286: try { ohair@286: if( ('-'+plugin.getOptionName()).equals(args[i]) ) { ohair@286: activePlugins.add(plugin); ohair@286: plugin.onActivated(this); ohair@286: pluginURIs.addAll(plugin.getCustomizationURIs()); ohair@286: ohair@286: // give the plugin a chance to parse arguments to this option. ohair@286: // this is new in 2.1, and due to the backward compatibility reason, ohair@286: // if plugin didn't understand it, we still return 1 to indicate ohair@286: // that this option is consumed. ohair@286: int r = plugin.parseArgument(this,args,i); ohair@286: if(r!=0) ohair@286: return r; ohair@286: else ohair@286: return 1; ohair@286: } ohair@286: ohair@286: int r = plugin.parseArgument(this,args,i); ohair@286: if(r!=0) return r; ohair@286: } catch (IOException e) { ohair@286: throw new BadCommandLineException(e.getMessage(),e); ohair@286: } ohair@286: } ohair@286: ohair@286: return 0; // unrecognized ohair@286: } ohair@286: ohair@286: private void parseProxy(String text) throws BadCommandLineException { ohair@286: // syntax is [user[:password]@]proxyHost:proxyPort ohair@286: String token = "([^@:]+)"; ohair@286: Pattern p = Pattern.compile("(?:"+token+"(?:\\:"+token+")?\\@)?"+token+"(?:\\:"+token+")"); ohair@286: ohair@286: Matcher matcher = p.matcher(text); ohair@286: if(!matcher.matches()) ohair@286: throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY,text)); ohair@286: ohair@286: proxyUser = matcher.group(1); ohair@286: proxyPassword = matcher.group(2); ohair@286: proxyHost = matcher.group(3); ohair@286: proxyPort = matcher.group(4); ohair@286: try { ohair@286: Integer.valueOf(proxyPort); ohair@286: } catch (NumberFormatException e) { ohair@286: throw new BadCommandLineException(Messages.format(Messages.ILLEGAL_PROXY,text)); ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Obtains an operand and reports an error if it's not there. ohair@286: */ ohair@286: public String requireArgument(String optionName, String[] args, int i) throws BadCommandLineException { ohair@286: if (i == args.length || args[i].startsWith("-")) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.MISSING_OPERAND,optionName)); ohair@286: } ohair@286: return args[i]; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Parses a token to a file (or a set of files) ohair@286: * and add them as {@link InputSource} to the specified list. ohair@286: * ohair@286: * @param suffix ohair@286: * If the given token is a directory name, we do a recusive search ohair@286: * and find all files that have the given suffix. ohair@286: */ ohair@286: private void addFile(String name, List target, String suffix) throws BadCommandLineException { ohair@286: Object src; ohair@286: try { ohair@286: src = Util.getFileOrURL(name); ohair@286: } catch (IOException e) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.NOT_A_FILE_NOR_URL,name)); ohair@286: } ohair@286: if(src instanceof URL) { ohair@286: target.add(absolutize(new InputSource(Util.escapeSpace(((URL)src).toExternalForm())))); ohair@286: } else { ohair@286: File fsrc = (File)src; ohair@286: if(fsrc.isDirectory()) { ohair@286: addRecursive(fsrc,suffix,target); ohair@286: } else { ohair@286: target.add(absolutize(fileToInputSource(fsrc))); ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Adds a new catalog file. ohair@286: */ ohair@286: public void addCatalog(File catalogFile) throws IOException { ohair@286: if(entityResolver==null) { ohair@286: CatalogManager.getStaticManager().setIgnoreMissingProperties(true); ohair@286: entityResolver = new CatalogResolver(true); ohair@286: } ohair@286: ((CatalogResolver)entityResolver).getCatalog().parseCatalog(catalogFile.getPath()); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Parses arguments and fill fields of this object. ohair@286: * ohair@286: * @exception BadCommandLineException ohair@286: * thrown when there's a problem in the command-line arguments ohair@286: */ ohair@286: public void parseArguments( String[] args ) throws BadCommandLineException { ohair@286: ohair@286: for (int i = 0; i < args.length; i++) { ohair@286: if(args[i].length()==0) ohair@286: throw new BadCommandLineException(); ohair@286: if (args[i].charAt(0) == '-') { ohair@286: int j = parseArgument(args,i); ohair@286: if(j==0) ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.UNRECOGNIZED_PARAMETER, args[i])); ohair@286: i += (j-1); ohair@286: } else { ohair@286: if(args[i].endsWith(".jar")) ohair@286: scanEpisodeFile(new File(args[i])); ohair@286: else ohair@286: addFile(args[i],grammars,".xsd"); ohair@286: } ohair@286: } ohair@286: ohair@286: // configure proxy ohair@286: if (proxyHost != null || proxyPort != null) { ohair@286: if (proxyHost != null && proxyPort != null) { ohair@286: System.setProperty("http.proxyHost", proxyHost); ohair@286: System.setProperty("http.proxyPort", proxyPort); ohair@286: System.setProperty("https.proxyHost", proxyHost); ohair@286: System.setProperty("https.proxyPort", proxyPort); ohair@286: } else if (proxyHost == null) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.MISSING_PROXYHOST)); ohair@286: } else { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.MISSING_PROXYPORT)); ohair@286: } ohair@286: if(proxyUser!=null) ohair@286: System.setProperty("http.proxyUser", proxyUser); ohair@286: if(proxyPassword!=null) ohair@286: System.setProperty("http.proxyPassword", proxyPassword); ohair@286: ohair@286: } ohair@286: ohair@286: if (grammars.isEmpty()) ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.MISSING_GRAMMAR)); ohair@286: ohair@286: if( schemaLanguage==null ) ohair@286: schemaLanguage = guessSchemaLanguage(); ohair@286: ohair@286: // if(target==SpecVersion.V2_2 && !isExtensionMode()) ohair@286: // throw new BadCommandLineException( ohair@286: // "Currently 2.2 is still not finalized yet, so using it requires the -extension switch." + ohair@286: // "NOTE THAT 2.2 SPEC MAY CHANGE BEFORE IT BECOMES FINAL."); ohair@286: ohair@286: if(pluginLoadFailure!=null) ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.PLUGIN_LOAD_FAILURE,pluginLoadFailure)); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Finds the META-INF/sun-jaxb.episode file to add as a binding customization. ohair@286: */ ohair@286: public void scanEpisodeFile(File jar) throws BadCommandLineException { ohair@286: try { ohair@286: URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()}); ohair@286: Enumeration resources = ucl.findResources("META-INF/sun-jaxb.episode"); ohair@286: while (resources.hasMoreElements()) { ohair@286: URL url = resources.nextElement(); ohair@286: addBindFile(new InputSource(url.toExternalForm())); ohair@286: } ohair@286: } catch (IOException e) { ohair@286: throw new BadCommandLineException( ohair@286: Messages.format(Messages.FAILED_TO_LOAD,jar,e.getMessage()), e); ohair@286: } ohair@286: } ohair@286: ohair@286: ohair@286: /** ohair@286: * Guesses the schema language. ohair@286: */ ohair@286: public Language guessSchemaLanguage() { ohair@286: ohair@286: // otherwise, use the file extension. ohair@286: // not a good solution, but very easy. ohair@286: if ((grammars != null) && (grammars.size() > 0)) { ohair@286: String name = grammars.get(0).getSystemId().toLowerCase(); ohair@286: ohair@286: if (name.endsWith(".rng")) ohair@286: return Language.RELAXNG; ohair@286: if (name.endsWith(".rnc")) ohair@286: return Language.RELAXNG_COMPACT; ohair@286: if (name.endsWith(".dtd")) ohair@286: return Language.DTD; ohair@286: if (name.endsWith(".wsdl")) ohair@286: return Language.WSDL; ohair@286: } ohair@286: ohair@286: // by default, assume XML Schema ohair@286: return Language.XMLSCHEMA; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Creates a configured CodeWriter that produces files into the specified directory. ohair@286: */ ohair@286: public CodeWriter createCodeWriter() throws IOException { ohair@286: return createCodeWriter(new FileCodeWriter( targetDir, readOnly, encoding )); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Creates a configured CodeWriter that produces files into the specified directory. ohair@286: */ ohair@286: public CodeWriter createCodeWriter( CodeWriter core ) { ohair@286: if(noFileHeader) ohair@286: return core; ohair@286: ohair@286: return new PrologCodeWriter( core,getPrologComment() ); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets the string suitable to be used as the prolog comment baked into artifacts. ohair@286: * This is the string like "This file was generated by the JAXB RI on YYYY/mm/dd..." ohair@286: */ ohair@286: public String getPrologComment() { ohair@286: // generate format syntax: 'at'