/*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Intalio, Inc. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Intalio, Inc. Exolab is a registered
* trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved.
*
* This file was originally developed by Keith Visco during the
* course of employment at Intalio Inc.
* All portions of this file developed by Keith Visco after Jan 19 2005 are
* Copyright (C) 2005 Keith Visco. All Rights Reserved.
*
* $Id: $
*/
package org.exolab.castor.builder;
import java.io.PrintWriter;
import java.util.Properties;
import org.exolab.castor.builder.binding.BindingException;
import org.exolab.castor.builder.binding.BindingLoader;
import org.exolab.castor.builder.factory.FieldInfoFactory;
import org.exolab.castor.util.CommandLineOptions;
import org.xml.sax.InputSource;
/**
* Main line method for command-line invokation of the source generation tool.
* Because this class exists only to provide a main(String[]) for command-line
* use, all methods are static.
*
* @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> - Main author.
* @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a> - Contributions.
* @author <a href="mailto:nsgreen@thazar.com">Nathan Green</a> - Contributions.
* @author <a href="mailto:edward.kuns@aspect.com">Edward Kuns</a> - Cut out of SourceGenerator.java
* @version $Revision: 0000 $ $Date: $
*/
public final class SourceGeneratorMain {
//--------------------------/
//- Command line arguments -/
//--------------------------/
private static final String ARGUMENT_BINDING_FILENAME = "binding-file";
private static final String ARGUMENT_CASE_INSENSITIVE = "case-insensitive";
private static final String ARGUMENT_DESTINATION_DIR = "dest";
private static final String ARGUMENT_DISABLE_DESCRIPTORS = "nodesc";
private static final String ARGUMENT_FORCE = "f";
private static final String ARGUMENT_GENERATE_IMPORTED_SCHEMAS = "generateImportedSchemas";
private static final String ARGUMENT_GENERATE_MAPPING = "gen-mapping";
private static final String ARGUMENT_HELP = "h";
private static final String ARGUMENT_INPUT = "i";
private static final String ARGUMENT_INPUT_SOURCE = "is";
private static final String ARGUMENT_LINE_SEPARATOR = "line-separator";
private static final String ARGUMENT_NOMARSHALL = "nomarshall";
private static final String ARGUMENT_PACKAGE = "package";
private static final String ARGUMENT_RESOURCES_DESTINATION_DIR = "resourcesDestination";
private static final String ARGUMENT_SAX1 = "sax1";
private static final String ARGUMENT_TESTABLE = "testable";
private static final String ARGUMENT_TYPES = "types";
private static final String ARGUMENT_TYPES_DEPRECATED = "type-factory";
private static final String ARGUMENT_TYPES_JAVA2 = "j2";
private static final String ARGUMENT_VERBOSE = "verbose";
private static final String ARGUMENT_FAIL_ON_ERROR = "fail";
private static final String ARGUMENT_NAME_CONFLICT_STRATEGY = "nameConflictStrategy";
private static final String ARGUMENT_NAME_JCLASSPRINTER = "classPrinter";
private static final String ARG_VALUE_LINE_SEPARATION_MAC = "mac";
private static final String ARG_VALUE_LINE_SEPARATION_UNIX = "unix";
private static final String ARG_VALUE_LINE_SEPARATION_WIN = "win";
//-------------------------/
//- Command line messages -/
//-------------------------/
/** Message used when descriptor creation is disabled. */
private static final String DISABLE_DESCRIPTORS_MSG =
"Disabling generation of Class descriptors.";
/** Message used when marshaling methods creation is disabled. */
private static final String DISABLE_MARSHALL_MSG =
"Disabling generation of Marshaling framework methods (marshal, unmarshal, validate).";
/** Message used when implementing CastorTestable. */
private static final String CASTOR_TESTABLE_MSG =
"The generated classes will implement org.castor.xmlctf.CastorTestable.";
/** Message used when using SAX1. */
private static final String SAX1_MSG =
"The generated classes will use SAX 1.";
private static final String GENERATE_IMPORT_MSG =
"Imported XML Schemas will be processed automatically.";
private static final String CASE_INSENSITIVE_MSG =
"The generated classes will use a case insensitive method "
+ "for looking up enumerated type values.";
private static final String TYPE_FACTORY_ARG_MSG =
"The argument '-type-factory' is deprecated; please use '-types' in its place.";
private static final String SUPPRESS_NON_FATAL_WARN_MSG =
"Suppressing non fatal warnings.";
private static final String GENERATING_MAPPING_FILE_MSG =
"Generating mapping file: ";
private static final String BINDING_FILE_ERROR1_MSG =
"Unable to load binding file ";
private static final String BINDING_FILE_ERROR2_MSG =
" due to the following Exception:";
private static final String BINDING_FILE_ERROR3_MSG =
"No binding file will be used.";
private static final String INVALID_TYPES_OPTION_MSG =
"Invalid option for '-types': ";
private static final String DEFAULT_FIELD_INFO_MSG =
"Using default source generator types.";
private static final String LINE_SEPARATION_WIN_MSG =
"Using Windows style line separation.";
private static final String LINE_SEPARATION_UNIX_MSG =
"Using UNIX style line separation.";
private static final String LINE_SEPARATION_MAC_MSG =
"Using Macintosh style line separation.";
private static final String DEFAULT_LINE_SEPARATOR_MSG =
"Using default line separator for this platform";
private static final String INVALID_LINE_SEPARATOR_MSG =
"Invalid option for line-separator: ";
private static final String NAME_CONFLICT_STRATEGY_MSG =
"Using name conflict strategy ";
private static final String JCLASSPRINTER_TYPE_MSG =
"Using JClass printing type ";
private static final String USING_SEPARATE_RESOURCES_DIRECTORY =
"Using a separate destination for resources.";
/** The full set of command-line options. */
private static final CommandLineOptions ALL_OPTIONS = setupCommandLineOptions();
/**
* As a static utility class, we want a private constructor.
*/
private SourceGeneratorMain() {
// Private constructor
}
//////////////////
// MAIN METHOD //
//////////////////
/**
* Parses the command line, converting everything into the proper form for
* the source generation main class, then invokes source generation.
*
* @param args the String[] consisting of the command line arguments
*/
public static void main(final String[] args) {
//-- Process the specified command line options
Properties options = ALL_OPTIONS.getOptions(args);
//-- check for help option
if (options.getProperty(ARGUMENT_HELP) != null) {
PrintWriter pw = new PrintWriter(System.out, true);
ALL_OPTIONS.printHelp(pw);
return;
}
//-- Make sure we have a schema to work on
String schemaFilename = options.getProperty(ARGUMENT_INPUT);
String schemaURL = options.getProperty(ARGUMENT_INPUT_SOURCE);
if (schemaFilename == null && schemaURL == null) {
System.out.println(SourceGenerator.APP_NAME);
ALL_OPTIONS.printUsage(new PrintWriter(System.out));
return;
}
// Instantiate our SourceGenerator
FieldInfoFactory factory = getTypeFactory(options);
SourceGenerator sgen = (factory == null) ? new SourceGenerator()
: new SourceGenerator(factory);
// Everything below here sets options on our SourceGenerator
sgen.setLineSeparator(getLineSeparator(options.getProperty(ARGUMENT_LINE_SEPARATOR)));
sgen.setDestDir(options.getProperty(ARGUMENT_DESTINATION_DIR));
// set a resource destination if specified
String resourcesDestination = options.getProperty(ARGUMENT_RESOURCES_DESTINATION_DIR);
if (resourcesDestination != null) {
sgen.setResourceDestination(resourcesDestination);
System.out.print("-- ");
System.out.println(USING_SEPARATE_RESOURCES_DIRECTORY);
}
sgen.setVerbose(options.getProperty(ARGUMENT_VERBOSE) != null);
sgen.setFailOnFirstError(options.getProperty(ARGUMENT_FAIL_ON_ERROR) != null);
boolean force = (options.getProperty(ARGUMENT_FORCE) != null);
sgen.setSuppressNonFatalWarnings(force);
if (force) {
System.out.print("-- ");
System.out.println(SUPPRESS_NON_FATAL_WARN_MSG);
}
if (options.getProperty(ARGUMENT_DISABLE_DESCRIPTORS) != null) {
sgen.setDescriptorCreation(false);
System.out.print("-- ");
System.out.println(DISABLE_DESCRIPTORS_MSG);
}
String mappingFilename = options.getProperty(ARGUMENT_GENERATE_MAPPING);
if (mappingFilename != null) {
sgen.setGenerateMappingFile(true);
if (mappingFilename.length() > 0) {
sgen.setMappingFilename(mappingFilename);
}
System.out.print("-- ");
System.out.println(GENERATING_MAPPING_FILE_MSG + "'" + mappingFilename + "'");
}
if (options.getProperty(ARGUMENT_NOMARSHALL) != null) {
sgen.setCreateMarshalMethods(false);
System.out.print("-- ");
System.out.println(DISABLE_MARSHALL_MSG);
}
if (options.getProperty(ARGUMENT_TESTABLE) != null) {
sgen.setTestable(true);
System.out.print("-- ");
System.out.println(CASTOR_TESTABLE_MSG);
}
if (options.getProperty(ARGUMENT_SAX1) != null) {
sgen.setSAX1(true);
System.out.print("-- ");
System.out.println(SAX1_MSG);
}
if (options.getProperty(ARGUMENT_CASE_INSENSITIVE) != null) {
sgen.setCaseInsensitive(true);
System.out.print("-- ");
System.out.println(CASE_INSENSITIVE_MSG);
}
String nameConflictStrategy = options.getProperty(ARGUMENT_NAME_CONFLICT_STRATEGY);
if (nameConflictStrategy != null) {
sgen.setNameConflictStrategy(nameConflictStrategy);
System.out.print("-- ");
System.out.println(CASE_INSENSITIVE_MSG + nameConflictStrategy);
}
String jClassPrinterType = options.getProperty(ARGUMENT_NAME_JCLASSPRINTER);
if (jClassPrinterType != null) {
sgen.setJClassPrinterType(jClassPrinterType);
System.out.print("-- ");
System.out.println(JCLASSPRINTER_TYPE_MSG + jClassPrinterType);
}
String bindingFilename = options.getProperty(ARGUMENT_BINDING_FILENAME);
if (bindingFilename != null) {
try {
sgen.setBinding(BindingLoader.createBinding(bindingFilename));
} catch (BindingException e) {
System.out.print("--");
System.out.println(BINDING_FILE_ERROR1_MSG + "'" + bindingFilename + "'"
+ BINDING_FILE_ERROR2_MSG);
e.printStackTrace();
System.out.print("--");
System.out.println(BINDING_FILE_ERROR3_MSG);
}
}
if (options.getProperty(ARGUMENT_GENERATE_IMPORTED_SCHEMAS) != null) {
sgen.setGenerateImportedSchemas(true);
System.out.print("-- ");
System.out.println(GENERATE_IMPORT_MSG);
}
try {
if (schemaFilename != null) {
sgen.generateSource(schemaFilename, options.getProperty(ARGUMENT_PACKAGE));
} else if (schemaURL != null) {
sgen.generateSource(new InputSource(schemaURL), options.getProperty(ARGUMENT_PACKAGE));
}
} catch (Exception ex) {
ex.printStackTrace();
}
} //-- main
/**
* Creates and returns a <code>FieldInfoFactory</code> (or null if none
* requested or if an error is encountered making the requested type) to be
* used during source generation. If the <code>-types</code> argument is
* not found, check for the deprecated but still supported
* <code>-type-factory</code> argument. If we find that, give a
* deprecation warning.
* <p>
* Once we've parsed the command-line arguments, if there are no arguemnts
* appropriate for a type factory, then we have nothing to do. Otherwise,
* try to instantiate the requested <code>FieldInfoFactory</code>. If the
* <code>FieldInfoFactory</code> throws an
* <code>IllegalArgumentException</code> then try to instantiate the class
* provided, which allows someone to provide their own implementation of a
* <code>FieldInfoFactory</code>, which must extend (@link
* org.exolab.castor.builder.FieldInfoFactory).
*
* @param options the full set of command-line options
* @return a FieldInfoFactory to be used during source generation, or null
* if the default should be used
* @see org.exolab.castor.builder.FieldInfoFactory
*/
private static FieldInfoFactory getTypeFactory(final Properties options) {
String typeFactory = options.getProperty(ARGUMENT_TYPES);
if (typeFactory == null) {
// This backwards-compatible option is retained temporarily
typeFactory = options.getProperty(ARGUMENT_TYPES_DEPRECATED);
if (typeFactory != null) {
System.out.print("-- ");
System.out.println(TYPE_FACTORY_ARG_MSG);
}
}
//-- For backwards compatibility
if (typeFactory != null && typeFactory.equals(ARGUMENT_TYPES_JAVA2)) {
typeFactory = "arraylist";
}
// If no command-line arguments, then we have nothing to do
if (typeFactory == null) {
return null;
}
FieldInfoFactory factory = null;
try {
factory = new FieldInfoFactory(typeFactory);
} catch (IllegalArgumentException e) {
try {
// Allow someone to provide their own FieldInfoFactory implementation
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
factory = (FieldInfoFactory) classLoader.loadClass(typeFactory).newInstance();
} catch (Exception e2) {
System.out.println("-- " + INVALID_TYPES_OPTION_MSG + typeFactory);
System.out.println("-- " + e.getMessage());
System.out.println("-- " + DEFAULT_FIELD_INFO_MSG);
}
}
return factory;
}
/**
* Parses the command-line argument for line separator style, handles bad
* values, and returns a value that the source generator will understand.
*
* @param lineSepStyle the command-line argument for line separation style
* @return the line separator string as the source generator understands it.
*/
private static String getLineSeparator(final String lineSepStyle) {
String lineSep = System.getProperty("line.separator");
if (lineSepStyle != null) {
if (ARG_VALUE_LINE_SEPARATION_WIN.equals(lineSepStyle)) {
System.out.println("-- " + LINE_SEPARATION_WIN_MSG);
lineSep = "\r\n";
} else if (ARG_VALUE_LINE_SEPARATION_UNIX.equals(lineSepStyle)) {
System.out.println("-- " + LINE_SEPARATION_UNIX_MSG);
lineSep = "\n";
} else if (ARG_VALUE_LINE_SEPARATION_MAC.equals(lineSepStyle)) {
System.out.println("-- " + LINE_SEPARATION_MAC_MSG);
lineSep = "\r";
} else {
System.out.println("-- " + INVALID_LINE_SEPARATOR_MSG + "'" + lineSepStyle + "'");
System.out.println("-- " + DEFAULT_LINE_SEPARATOR_MSG);
}
}
return lineSep;
}
/**
* Configures our command-line options object with the command line options
* that we recognize.
*
* @return a new CommandLineOptions object fully configured to parse our
* command line.
*/
private static CommandLineOptions setupCommandLineOptions() {
CommandLineOptions allOptions = new CommandLineOptions();
String desc;
//-- filename flag
desc = "Sets the filename for the schema used as input.";
allOptions.addFlag(ARGUMENT_INPUT, "schema filename", desc);
//-- filename flag
desc = "Sets the input source for the schema used as input.";
allOptions.addFlag(ARGUMENT_INPUT_SOURCE, "input source for XML schema", desc);
//-- package name flag
desc = "Sets the package name for generated code.";
allOptions.addFlag(ARGUMENT_PACKAGE, "package name", desc, true);
//-- destination directory
desc = "Sets the destination output directory.";
allOptions.addFlag(ARGUMENT_DESTINATION_DIR, "destination directory", desc, true);
//-- resources destination directory
desc = "Sets the destination output directory for resources.";
allOptions.addFlag(ARGUMENT_RESOURCES_DESTINATION_DIR, "resources destination directory", desc, true);
//-- line break flag
desc = "Sets the line separator style for the desired platform.";
allOptions.addFlag(ARGUMENT_LINE_SEPARATOR, "(unix | mac | win)", desc, true);
//-- Force flag
desc = "Suppresses non fatal warnings, such as overwriting files.";
allOptions.addFlag(ARGUMENT_FORCE, "", desc, true);
//-- Help flag
desc = "Displays this help screen.";
allOptions.addFlag(ARGUMENT_HELP, "", desc, true);
//-- verbose flag
desc = "Prints out additional messages when creating source.";
allOptions.addFlag(ARGUMENT_VERBOSE, "", desc, true);
//-- fail on first error flag
desc = "Causes source generation to fail on the first error encountered.";
allOptions.addFlag(ARGUMENT_FAIL_ON_ERROR, "", desc, true);
//-- no descriptors flag
desc = "Disables the generation of the Class descriptors.";
allOptions.addFlag(ARGUMENT_DISABLE_DESCRIPTORS, "", desc, true);
//-- mapping file flag
desc = "Indicates that a mapping file should be generated.";
allOptions.addFlag(ARGUMENT_GENERATE_MAPPING, "mapping filename", desc, true);
//-- source generator types name flag
desc = "Sets the source generator types name (SGTypeFactory).";
allOptions.addFlag(ARGUMENT_TYPES, "types", desc, true);
//-- We temporarily maintain backwards compatibility, but this argument is deprecated
desc = "";
allOptions.addFlag(ARGUMENT_TYPES_DEPRECATED, "collections class name", desc, true);
//-- no marshaling framework methods
desc = "Disables the generation of the methods specific to the XML marshaling framework.";
allOptions.addFlag(ARGUMENT_NOMARSHALL, "", desc, true);
//-- implements org.castor.xmlctf.CastorTestable?
desc = "Implements some specific methods to allow the generated classes"
+ " to be used with Castor Testing Framework.";
allOptions.addFlag(ARGUMENT_TESTABLE, "", desc, true);
//-- use SAX1?
desc = "Uses SAX 1 in the generated code.";
allOptions.addFlag(ARGUMENT_SAX1, "", desc, true);
//-- Source Generator Binding
desc = "Sets the Source Generator Binding File name.";
allOptions.addFlag(ARGUMENT_BINDING_FILENAME, "filename", desc, true);
//-- Generates sources for imported XML Schemas
desc = "Generates sources for imported XML schemas.";
allOptions.addFlag(ARGUMENT_GENERATE_IMPORTED_SCHEMAS, "", desc, true);
//-- Sets enumerated type to use a case insensitive lookup
desc = "Sets enumerated types to use a case insensitive lookup.";
allOptions.addFlag(ARGUMENT_CASE_INSENSITIVE, "", desc);
//-- Sets enumerated type to use a case insensitive lookup
desc = "Sets name conflict strategy to use (possible values are "
+ "'informViaLog', 'warnViaConsoleDialog').";
allOptions.addFlag(ARGUMENT_NAME_CONFLICT_STRATEGY, "", desc);
desc = "Selects the JClass printer type (default 'standard')";
allOptions.addFlag(ARGUMENT_NAME_JCLASSPRINTER, "<mode>", desc, true);
return allOptions;
}
}