/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *******************************************************************************/ package org.ebayopensource.turmeric.tools.codegen; import static org.ebayopensource.turmeric.tools.codegen.util.CodeGenConstants.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager; import org.ebayopensource.turmeric.tools.codegen.exception.BadInputOptionException; import org.ebayopensource.turmeric.tools.codegen.exception.BadInputValueException; import org.ebayopensource.turmeric.tools.codegen.exception.CodeGenFailedException; import org.ebayopensource.turmeric.tools.codegen.exception.MissingInputOptionException; import org.ebayopensource.turmeric.tools.codegen.exception.PreValidationFailedException; import org.ebayopensource.turmeric.tools.codegen.handler.ConsoleResponseHandler; import org.ebayopensource.turmeric.tools.codegen.handler.UserResponseHandler; import org.ebayopensource.turmeric.tools.codegen.util.CodeGenClassLoader; import org.ebayopensource.turmeric.tools.codegen.util.CodeGenUtil; import org.ebayopensource.turmeric.tools.codegen.util.JavaToolsClassLoader; /** * Service generator provides higher-level API for code generation tools. * * * @author rmandapati */ public class ServiceGenerator { private static final String CODEGEN_BUILDER_CLASS = "org.ebayopensource.turmeric.tools.codegen.ServiceCodeGenBuilder"; private static Logger s_logger = LogManager.getInstance(ServiceGenerator.class); private static String s_printUsage = null; private UserResponseHandler m_responseHandler = null; public static String s_JavaHome; public static String s_JdkHome; private boolean useClassLoader = true; // Includes classes from these packages to be loadable by CodeGenClassLoader private static String[] s_inclPackagePrefixes = { "org.apache.axis2", "org.codehaus", "org.ebayopensource.turmeric.runtime" }; // Excludes classes from these packages from loading by CodeGenClassLoader private static final String[] s_exclPackagePrefixes = { "org.ebayopensource.turmeric.runtime.tools.codegen.exception", "org.ebayopensource.turmeric.runtime.tools.codegen.handler" }; // Excludes classes from loading by CodeGenClassLoader private static final String[] s_exclClasses = { "org.ebayopensource.turmeric.runtime.tools.codegen.util.CodeGenClassLoader" }; public ServiceGenerator() { setUserResponseHandler(new ConsoleResponseHandler()); } public ServiceGenerator(UserResponseHandler userResponseHandler) { setUserResponseHandler(userResponseHandler); } public UserResponseHandler getUserResponseHandler() { return m_responseHandler; } public void setUserResponseHandler(final UserResponseHandler responseHandler) { m_responseHandler = responseHandler; } public boolean isUseClassLoader() { return useClassLoader; } public void setUseClassLoader(boolean useClassLoader) { this.useClassLoader = useClassLoader; } /** * Initiates service code generation process * * @param String[] - Code generation options * @throws Exception */ public void startCodeGen(String[] args) throws Exception { parseArgs(args); performLoggingInit(args); if(this.useClassLoader) { ClassLoader classLoader = ServiceGenerator.class.getClassLoader(); if (classLoader == null) { classLoader = ClassLoader.getSystemClassLoader(); } ClassLoader peerClassLoader = null; if(Thread.currentThread().getContextClassLoader() != classLoader){ peerClassLoader = Thread.currentThread().getContextClassLoader(); } ClassLoader codeGenClassLoader = new CodeGenClassLoader(classLoader, peerClassLoader, s_inclPackagePrefixes, s_exclPackagePrefixes, s_exclClasses); startCodeGen(args, codeGenClassLoader); } else { Class<?> clazz = Class.forName(CODEGEN_BUILDER_CLASS); startCodeGen(args, clazz); } } private void performLoggingInit(String[] inputArgs) { String configFilePath = ""; for (int i = 0; i < inputArgs.length; i++) { if (inputArgs[i].equals(InputOptions.OPT_LOG_CONFIG_FILE) && ((i + 1) < inputArgs.length)) { configFilePath = inputArgs[i + 1]; if (configFilePath.startsWith("-")) configFilePath = ""; break; } } if (CodeGenUtil.isEmptyString(configFilePath)) { configFilePath = System.getProperty(CODEGEN_LOG_CONFIG); if (CodeGenUtil.isEmptyString(configFilePath)) configFilePath = System.getenv(CODEGEN_LOG_CONFIG); } LogManager.initilizeLoggingCriteria(configFilePath); } public void startCodeGen(String[] args, ClassLoader classLoader) throws Exception { String serviceCodeGenClassName = CODEGEN_BUILDER_CLASS; Class<?> codeGenRunner = classLoader.loadClass(serviceCodeGenClassName); startCodeGen(args, codeGenRunner); } public void startCodeGen(String[] args, Class<?> codeGenRunner) throws Exception { Object codeGenRunnerObj = codeGenRunner.newInstance(); Class paramType1 = String[].class; Class paramType2 = UserResponseHandler.class; Method codeGenRunMethod = codeGenRunner.getDeclaredMethod("build", paramType1, paramType2); try { Object[] runMethodParams = new Object[] { args, getUserResponseHandler() }; codeGenRunMethod.invoke(codeGenRunnerObj, runMethodParams); } catch (InvocationTargetException invocationTargetEx) { Throwable th = invocationTargetEx.getTargetException(); if (th instanceof BadInputOptionException) { throw (BadInputOptionException) th; } else if (th instanceof MissingInputOptionException) { throw (MissingInputOptionException) th; } else if (th instanceof BadInputValueException) { throw (BadInputValueException) th; } else if (th instanceof NoClassDefFoundError) { throw new CodeGenFailedException(th.toString(), th); } else if (th instanceof PreValidationFailedException) { throw (PreValidationFailedException) th; } else if (th instanceof Exception) { throw (Exception) th; } throw invocationTargetEx; } } static void initConsoleLogging(boolean enableDebugLogging) { Handler consoleLogHandler = new ConsoleOutHandler(); s_logger.addHandler(consoleLogHandler); Level logLevel = (enableDebugLogging ? Level.FINEST : Level.INFO); consoleLogHandler.setLevel(logLevel); s_logger.setLevel(logLevel); } private void parseArgs(String[] args) throws BadInputOptionException, BadInputValueException, MissingInputOptionException { if (args == null || args.length == 0) { throw new BadInputOptionException("Arguments for code generation missing"); } int i = 0; int argsLength = args.length; boolean isGentypeAvailable = false; boolean isInputXML = false; while (i < argsLength) { String optName = args[i].toLowerCase(); if (InputOptions.OPT_JAVA_HOME.equals(optName)) { i = getNextOptionIndex(i, args, optName, true); s_JavaHome = args[i]; System.setProperty("java.home", s_JavaHome); s_logger .log(Level.INFO, "java.home is being set to " + args[i]); } else if (InputOptions.OPT_JDK_HOME.equals(optName)) { i = getNextOptionIndex(i, args, optName, true); s_JdkHome = args[i]; s_logger .log(Level.INFO, "jdk home being used to " + args[i]); } else if(InputOptions.OPT_CODE_GEN_TYPE.equals(optName)){ i = getNextOptionIndex(i, args, optName, true); if(!CodeGenUtil.isEmptyString(args[i]) && !args[i].startsWith("-")) isGentypeAvailable = true; } else if(InputOptions.OPT_XML.equals(optName)) isInputXML = true; i++; } if(!isGentypeAvailable && !isInputXML){ throw new MissingInputOptionException("Gentype option is not provided. Pls provide " + "a value for " + InputOptions.OPT_CODE_GEN_TYPE + " option"); } } public static int getNextOptionIndex(int currentOptIndex, String[] args, String optionName,boolean shouldHaveValue) throws BadInputOptionException,BadInputValueException { int nextOptionIndex = currentOptIndex + 1; if (nextOptionIndex >= args.length) { throw new BadInputValueException("Missing parameter for '" + args[currentOptIndex] + "' option."); } if(args[nextOptionIndex].startsWith("-") && shouldHaveValue){ String errMsg = "Please provide a value for the option " + optionName; throw new BadInputValueException(errMsg); } String nextArgument = args[nextOptionIndex]; if(CodeGenUtil.isEmptyString(nextArgument.trim())){ String errMsg = "Please provide a proper value for the option " + optionName; throw new BadInputValueException(errMsg); } return nextOptionIndex; } static void main(final String[] args) throws Exception { ServiceGenerator serviceGenerator = new ServiceGenerator(); try { boolean enableDebugLogging = false; for (int i = 0; i < args.length; i++) { if (InputOptions.OPT_VERBOSE.equalsIgnoreCase(args[i])) { enableDebugLogging = true; break; } } initConsoleLogging(enableDebugLogging); serviceGenerator.startCodeGen(args); } catch (BadInputOptionException badInputEx) { s_logger.log(Level.SEVERE, "Code gen failed, bad input options specified : ", badInputEx); s_logger.log(Level.FINE, getUsage()); throw badInputEx; } catch (MissingInputOptionException missingInputEx) { s_logger.log(Level.SEVERE, "Code gen failed, required input option is missing : ", missingInputEx); s_logger.log(Level.FINE, getUsage()); throw missingInputEx; } catch(CodeGenFailedException cfe){ s_logger.log(Level.SEVERE, "Code gen failed, while trying to generate artifacts : ", cfe); throw cfe; } catch (Exception ex) { s_logger.log(Level.SEVERE,"Code gen failed : ", ex); throw ex; } } /** * Code generation tool usage * * <pre> * * Usage: java -classpath <classpath> org.ebayopensource.turmeric.runtime.tools.codegen.ServiceGeneratorFacade [Options . . . .] * * -serviceName <ServiceName> : Name of the service * -namespace <NamespaceURI> : Namespace URI of the service * -interface|-class|-xml|-wsdl <file> : Type of input file, should specify fully qualified file/path * -gentype <CodeGenType> : Which files need to be generated * {All|Client|ClientNoConfig|Server|ServerNoConfig|Proxy|Dispatcher|ConfigAll|ClientConfig|ServerConfig| * GlobalServerConfig|GlocalClientConfig|Wsdl|Interface|Schema|SISkeleton|TypeMappings|WebXml|UnitTest| * TestClient|ServiceOpProps|SecurityPolicyConfig|ServiceMetadataProps} * -src <Dir> : Location of source files (incase of -interface/-class options) * -dest <Dir> : Generated files will go into this directory under gen-src and gen-meta-src * -jdest <Dir> : Destination location for generated Java source files * -mdest <Dir> : Destination location for generated configuration and other XML files * -bin <Dir> : Compiled classes will go into this directory * -sicn <ServiceImplClassName> : Qualified Service Implementation class name * -gin <GenInterfaceName> : Name for the generated interface (incase of -interface/-class/-wsdl options) * -gip <GenInterfacePackage> : Package name for the generated interface (incase of -interface/-class/-wsdl options) * -cn <ClientName> : Name of the client application * -scv <ServiceCurrVersion> : Current version of the Service * -ccgn <ClientCfgGroupName> : Client Config Group Name * -scgn <ServiceCfgGroupName> : Server Config Group Name * -op2cemc <all=cemc|op1=cemc1,...> : Service operation name to Custom error message class mapping * -pkg2ns <pkg1=ns1,pkg2=ns2> : Java Package to Namespace mapping * -ngc : Don't generate global configuration files * -gss : Generate Service Impl Skeleton * -icsi : Make ServiceImpl implement Common Service operations interface * -avi : Add Validate Internals for this Service * -slayer <ServiceLayer> : Layer to which Service belongs to, valid values are [INFRASTRUCTURE|APPLICATION|BUSINESS|INTEGRATION] * -sl <ServiceLocationURL> : Service Location * -wl <WSDLLocationURL> : WSDL Location * -gt : Generate Unit Testcase and Test client classes * -nc : Don't compile generated java source files (No-Compile) * -ce : Continue with rest of the code generation when an error occurs * -dlw : Generated Doc/Lit/Wrap style WSDL, default is Doc/Lit/Bare * -dontprompt : Supresses prompt messages * -verbose : Display more debug messages * -help : Displays this Help / Usage information * * </pre> * * @return Code generation tool usage string */ public static String getUsage() { if (s_printUsage == null) { String NEW_LINE = "\012"; StringBuffer strBuff = new StringBuffer(); strBuff.append(NEW_LINE); strBuff.append("Usage: java -classpath <classpath> org.ebayopensource.turmeric.runtime.tools.codegen.ServiceGeneratorFacade [Options . . . .]").append(NEW_LINE).append(NEW_LINE); strBuff.append("-serviceName <ServiceName> : Name of the service").append(NEW_LINE); strBuff.append("-namespace <NamespaceURI> : Namespace URI of the service").append(NEW_LINE); strBuff.append("-interface|-class|-xml|-wsdl <file> : Type of the input file, should specify fully qualified file (path)").append(NEW_LINE); strBuff.append("-gentype <CodeGenType> : Which files need to be generated {All|Client|ClientNoConfig|Server|ServerNoConfig|Proxy|Dispatcher|ConfigAll|ClientConfig|ServerConfig|"); strBuff.append(" GlobalServerConfig|GlocalClientConfig|Wsdl|Interface|Schema|SISkeleton|TypeMappings|TypeDefs|WebXml|UnitTest|"); strBuff.append(" TestClient|ServiceOpProps|SecurityPolicyConfig|ServiceMetadataProps}").append(NEW_LINE); strBuff.append("-src <Dir> : Location of source files").append(NEW_LINE); strBuff.append("-dest <Dir> : Generated files will go into this directory under gen-src and gen-meta-src").append(NEW_LINE); strBuff.append("-jdest <Dir> : Destination location for generated Java source files").append(NEW_LINE); strBuff.append("-mdest <Dir> : Destination location for generated configuration and other XML files").append(NEW_LINE); strBuff.append("-bin <Dir> : Compiled classes will go into this directory").append(NEW_LINE); strBuff.append("-pr <Dir> : Root path for the creation of the service_metadata.properties file").append(NEW_LINE); strBuff.append("-uij : Look for the service_metadata.properties file from the class path").append(NEW_LINE); strBuff.append("-sicn <ServiceImplClassName> : Qualified Service Implementation class name").append(NEW_LINE); strBuff.append("-gin <GenInterfaceName> : Name for the generated interface (for -interface/-class/-wsdl options)").append(NEW_LINE); strBuff.append("-gip <GenInterfacePackage> : Package name for the generated interface (for -interface/-class/-wsdl options)").append(NEW_LINE); strBuff.append("-cn <ClientName> : Name of the client application").append(NEW_LINE); strBuff.append("-scv <ServiceCurrVersion> : Current version of the Service").append(NEW_LINE); strBuff.append("-ccgn <ClientCfgGroupName> : Client Config Group Name").append(NEW_LINE); strBuff.append("-scgn <ServiceCfgGroupName> : Server Config Group Name").append(NEW_LINE); strBuff.append("-op2cemc <all=cemc|op1=cemc1,...> : Service operation name to Custom error message class mapping").append(NEW_LINE); strBuff.append("-pkg2ns <pkg1=ns1, pkg2=ns2> : Java Package to Namespace mapping").append(NEW_LINE); strBuff.append("-ns2pkg <ns1=pkg1, ns2=pkg2> : Namespace to Java Package mapping").append(NEW_LINE); strBuff.append("-ngc : Don't generate global configuration files").append(NEW_LINE); strBuff.append("-gss : Generate Service Impl Skeleton").append(NEW_LINE); strBuff.append("-icsi : Make ServiceImpl implement Common Service operations interface").append(NEW_LINE); strBuff.append("-avi : Add Validate Internals for this Service").append(NEW_LINE); strBuff.append("-asl <ServiceLayerFileLocation>: Location of the file containing the list of service layers").append(NEW_LINE); strBuff.append("-slayer <ServiceLayer> : Layer to which Service belongs to, pre-defined valid values are [COMMON|INTERMEDIATE|BUSINESS]").append(NEW_LINE); strBuff.append("-sl <ServiceLocationURL> : Service Location").append(NEW_LINE); strBuff.append("-wl <WSDLLocationURL> : WSDL Location").append(NEW_LINE); strBuff.append("-gt : Generate Unit Testcase and Test client classes").append(NEW_LINE); strBuff.append("-nc : Don't compile generated java source files (No-Compile)").append(NEW_LINE); strBuff.append("-ce : Continue with rest of the code generation when an error occurs").append(NEW_LINE); strBuff.append("-dlw : Generated Doc/Lit/Wrap style WSDL, default is Doc/Lit/Bare").append(NEW_LINE); strBuff.append("-dontprompt : Supresses prompt messages").append(NEW_LINE); strBuff.append("-verbose : Display more debug messages").append(NEW_LINE); strBuff.append("-lcf <LoggingConfigFile> : Location of codegen logging config file").append(NEW_LINE); strBuff.append("-help : Displays this Help / Usage information"); s_printUsage = strBuff.toString(); } return s_printUsage; } private static class ConsoleOutHandler extends ConsoleHandler { public ConsoleOutHandler() { super(); setOutputStream(System.out); //KEEPME } } }