/**
* Copyright 2011 meltmedia
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xchain.tools.executeplugin;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.surefire.booter.IsolatedClassLoader;
import org.xchain.tools.executeplugin.AbstractXChainMojo;
import org.hibernate.cfg.Configuration;
/**
* Configure Hibernate.
*
* Run an XChain.
*
* @author John Trimble
* @author Jason Rose
* @requiresDependencyResolution runtime
* @goal execute-xchain
*/
public class ExecuteMojo extends AbstractXChainMojo {
private static final String LIFE_CYCLE_CLASS_NAME = "org.xchain.framework.lifecycle.Lifecycle";
private static final String HIBERNATE_LIFE_CYCLE_CLASS_NAME = "org.xchain.framework.hibernate.HibernateLifecycle";
private static final String CONFIGURATION_CLASS_NAME = Configuration.class.getName();
private static final String CONFIGURATION_CONFIGURE_CONFIGURATION_METHOD = "configure";
private static final Class<?>[] CONFIGURATION_CONFIGURE_CONFIGURATION_ARGUMENTS = new Class<?>[] {File.class};
private static final String CONFIGURATION_SET_CONFIGURATION_METHOD = "setConfiguration";
private static final String CATALOG_FACTORY_CLASS_NAME = "org.xchain.framework.factory.CatalogFactory";
private static final String CATALOG_CLASS_NAME = "org.xchain.Catalog";
private static final String JXPATH_CONTEXT_CLASS_NAME = "org.apache.commons.jxpath.JXPathContext";
private static final String LIFE_CYCLE_START_LIFE_CYCLE_METHOD = "startLifecycle";
private static final String LIFE_CYCLE_STOP_LIFE_CYCLE_METHOD = "stopLifecycle";
private static final String COMMAND_CLASS_NAME = "org.xchain.Command";
private static final String CATALOG_FACTORY_INSTANCE_METHOD_NAME = "getInstance";
private static final String CATALOG_FACTORY_CATALOG_METHOD_NAME = "getCatalog";
private static final Class<?>[] CATALOG_FACTORY_CATALOG_ARGUMENT_TYPES = new Class<?>[] {String.class};
private static final String CATALOG_COMMAND_METHOD_NAME = "getCommand";
private static final Class<?>[] CATALOG_COMMAND_ARGUMENT_TYPES = new Class<?>[] {String.class};
private static final String COMMAND_EXECUTE_METHOD_NAME = "execute";
/**
* @parameter expression="${catalog}"
* @required
*/
private String catalog;
/**
* Configuration has to be a File because we don't have the url resolver available before the xchains lifecycle has started, so we can't resolve "resource://context-class-loader" urls.
* @parameter expression="${configuration}"
*/
private File configuration;
/**
* @parameter expression="${dispatcherCommand}" default-value="dispatcher"
* @required
*/
private String dispatcherCommand;
/**
* @parameter expression="${command}" default-value="update-to-latest-build"
*/
private String command;
/**
* @parameter default-value=false
*/
private boolean exportSchema;
/**
* @parameter default-value=true
*/
private boolean runXChainLifeCycle;
public void execute() throws MojoExecutionException, MojoFailureException {
ClassLoader chainClassLoader = createClassLoader(Thread.currentThread().getContextClassLoader(), this.classpathElements);
try {
Class<?> lifeCycleClass = chainClassLoader.loadClass(LIFE_CYCLE_CLASS_NAME);
Class<?> hibernateLifeCycleClass = chainClassLoader.loadClass(HIBERNATE_LIFE_CYCLE_CLASS_NAME);
Class<?> catalogFactoryClass = chainClassLoader.loadClass(CATALOG_FACTORY_CLASS_NAME);
Class<?> catalogClass = chainClassLoader.loadClass(CATALOG_CLASS_NAME);
Class<?> jxpathContextClass = chainClassLoader.loadClass(JXPATH_CONTEXT_CLASS_NAME);
Class<?> scopedJXPathContextClass = chainClassLoader.loadClass("org.xchain.framework.jxpath.ScopedJXPathContextImpl");
Class<?> contextFactoryClass = chainClassLoader.loadClass("org.xchain.framework.jxpath.JXPathContextFactoryImpl");
Class<?> scopedQNameVariablesClass = chainClassLoader.loadClass("org.xchain.framework.jxpath.ScopedQNameVariables");
Class<?> commandClass = chainClassLoader.loadClass(COMMAND_CLASS_NAME);
Class<?> configurationClass = chainClassLoader.loadClass(CONFIGURATION_CLASS_NAME);
// LifeCycle methods
Method startLifeCycleMethod = lifeCycleClass.getMethod(LIFE_CYCLE_START_LIFE_CYCLE_METHOD, new Class<?>[]{});
Method stopLifeCycleMethod = lifeCycleClass.getMethod(LIFE_CYCLE_STOP_LIFE_CYCLE_METHOD, new Class<?>[]{});
// CatalogFactory methods
Method getInstanceMethod = catalogFactoryClass.getMethod(CATALOG_FACTORY_INSTANCE_METHOD_NAME, new Class<?>[]{});
Method getCatalogMethod = catalogFactoryClass.getMethod(CATALOG_FACTORY_CATALOG_METHOD_NAME, CATALOG_FACTORY_CATALOG_ARGUMENT_TYPES);
// Catalog methods
Method getCommandMethod = catalogClass.getMethod(CATALOG_COMMAND_METHOD_NAME, CATALOG_COMMAND_ARGUMENT_TYPES);
// Command methods
Method executeMethod = commandClass.getMethod(COMMAND_EXECUTE_METHOD_NAME, jxpathContextClass);
// JXPathContext methods
Method newContextMethod = contextFactoryClass.getMethod("newContext", jxpathContextClass, Object.class);
Method declareVariableMethod = scopedQNameVariablesClass.getMethod("declareVariable", String.class, Object.class);
Method getVariablesMethod = scopedJXPathContextClass.getMethod("getVariables", new Class[] {});
// Configuration methods
Method configureMethod = configurationClass.getMethod(CONFIGURATION_CONFIGURE_CONFIGURATION_METHOD, CONFIGURATION_CONFIGURE_CONFIGURATION_ARGUMENTS);
Method setConfigurationMethod = hibernateLifeCycleClass.getMethod(CONFIGURATION_SET_CONFIGURATION_METHOD, configurationClass);
// Step 1: Switch Class loader
ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(chainClassLoader);
// Step 2: Configure Lifecycle
Object configurationObject = null;
if( configuration != null && configuration.exists() ) {
configurationObject = configurationClass.newInstance();
configurationObject = configureMethod.invoke(configurationObject, this.configuration);
setConfigurationMethod.invoke(null, new Object[]{configurationObject});
}
// Step 3: Start life cycle
if( this.runXChainLifeCycle ) startLifeCycleMethod.invoke(null, new Object[]{});
// Step 4: Get the catalog
Object catalogFactoryObject = getInstanceMethod.invoke(null, new Object[] {});
Object catalogObject = getCatalogMethod.invoke(catalogFactoryObject, new Object[] {this.catalog});
// Step 5: Get the command
Object commandObject = getCommandMethod.invoke(catalogObject, new Object[] {this.dispatcherCommand});
// Step 6: Configure the context
Object jxpathContextFactoryObject = contextFactoryClass.newInstance();
Object jxpathContextObject = newContextMethod.invoke(jxpathContextFactoryObject, null, new Object());
Object variablesObject = getVariablesMethod.invoke(jxpathContextObject, new Object[] {});
declareVariableMethod.invoke(variablesObject, "command", this.command);
declareVariableMethod.invoke(variablesObject, "exportSchema", this.exportSchema);
declareVariableMethod.invoke(variablesObject, "configuration", configurationObject);
// Step 7: Execute the command
executeMethod.invoke(commandObject, jxpathContextObject);
// Step 8: Stop life cycle
if( this.runXChainLifeCycle ) stopLifeCycleMethod.invoke(null, new Object[]{});
// Step 9: Switch Class loader back
Thread.currentThread().setContextClassLoader(originalContextClassLoader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
private ClassLoader createClassLoader(ClassLoader parent, Collection<String> classPathElementFilePaths) {
IsolatedClassLoader isolatedClassLoader = new IsolatedClassLoader(parent);
if( classPathElementFilePaths != null && classPathElementFilePaths.size() > 0 ) {
for( String classElementString : classPathElementFilePaths ) {
File classElementFile = new File(classElementString);
try {
URL url = classElementFile.toURL();
isolatedClassLoader.addURL(url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
return isolatedClassLoader;
}
}