/**
* 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;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import javax.xml.namespace.QName;
import org.apache.commons.jxpath.JXPathContext;
import org.hibernate.cfg.Configuration;
import org.xchain.framework.hibernate.HibernateLifecycle;
import org.xchain.framework.util.IoUtil;
/**
* <p>Bootstraps the environment for executing an XChain. It used an XML configuration file for
* determining what catalog to use and which commands to execute. It will also try and load in a Hibernate
* Configuration file and add it to the XChain Context.</p>
*
* @author Josh Kennedy
* @author Mike Moulton
*/
public class StandAloneHibernateExecutor extends StandAloneExecutor {
// XChain Configs
public static final String XCHAIN_EXECUTE = "{http://www.xchain.org/hibernate/}xchainEnabled";
public static final String XCHAIN_EXECUTE_ENV = "xchain_enabled";
// Deploy Data Source Configs
public static final String DEPLOY_DATASOURCE_CONFIGURATION = "{http://www.xchain.org/hibernate/}deploy_datasource";
public static final String DEPLOY_DATASOURCE_CONFIGURATION_ENV = "deploy_datasource";
public static final String DATASOURCE_CONFIGURATION = "{http://www.xchain.org/hibernate/}datasource";
public static final String DATABASE_CONFIGURATION = "{http://www.xchain.org/hibernate/}database";
public static final String DEPLOY_LOCATION = "{http://www.xchain.org/hibernate/}deploylocation";
public static final String DEPLOY_LOCATION_ENV = "DEPLOY_LOCATION";
// Shell Execution Config
public static final String COMMAND_EXECUTE_ENABLED = "{http://www.xchain.org/hibernate/}command_enabled";
public static final String COMMAND_EXECUTE_ENABLED_VAR = "command_enabled";
public static final String COMMAND_EXECUTE_SHELL = "{http://www.xchain.org/hibernate/}command_shell";
public static final String COMMAND_EXECUTE_SCRIPT = "{http://www.xchain.org/hibernate/}command_script";
public static final String COMMAND_EXECUTE_SHELL_DEFAULT = "bash";
public static final String CONFIGURATION_URI = "hibernate.configuration";
Configuration hibernateConfig;
/**
* Initalize the Hibernate specific Configurations
*/
public void initLifeCycle() {
if (this.getProperties().getProperty(CONFIGURATION_URI, null) != null && this.getProperties().getProperty(CONFIGURATION_URI).length() > 0) {
Configuration hibernateConfig = new Configuration();
hibernateConfig.configure(this.getProperties().getProperty(CONFIGURATION_URI));
HibernateLifecycle.setConfiguration(hibernateConfig);
}
}
/**
* Add the Hibernate config as a variable
*/
public void configureContext(JXPathContext context, Map<QName, Object> variables) {
super.configureContext(context, variables);
context.getVariables().declareVariable("configuration", hibernateConfig);
}
/**
* Used to copy datasource jndi configurations to the Application Server
* @param deployLocation
* @param dataSource
* @return int status 0 == good, > 0 == error
*/
protected int deployDatasource(String deployLocation, String dataSource) {
if (deployLocation == null || dataSource == null) {
log.warn("Both deploy location '{}' and datasource '{}' must be specified.", deployLocation, dataSource);
return DataSourceDeploy.CONFIGURATION_ERROR;
}
// Check if Deploy Directory exists
File deployDirectory = new File(deployLocation);
if (deployDirectory == null || !deployDirectory.exists() || !deployDirectory.isDirectory() || !deployDirectory.canWrite()) {
log.warn("Could not access Deploy directory '{}'.", deployDirectory.getAbsolutePath());
return DataSourceDeploy.DEPLOY_DESTINATION_NONEXISTENT;
}
InputStream datasourceConfiguration = null;
try {
datasourceConfiguration = IoUtil.getFileStream(dataSource, log);
} catch (FileNotFoundException e) {
log.warn("Could not access configuration file '{}'.", datasourceConfiguration);
return DataSourceDeploy.DATASOURCE_CONFIGURATION_NONEXISTENT;
}
File deployDatasourceFile = new File(deployDirectory, new File(dataSource).getName());
log.info("Destination file is '{}'.", deployDatasourceFile.getAbsolutePath());
if (IoUtil.fileCopy(datasourceConfiguration, deployDatasourceFile, log)) {
return DataSourceDeploy.SUCCESS;
}
else {
return DataSourceDeploy.DATASOURCE_COPY_FAILED;
}
}
protected int runCommands() {
// Find all of the Commands in the Executor XML
// For each one, copy the script to the local file system
// then execute it
// For now just enable the ability to run one command
// In order to run multiples the best approach would be a
// seperate xml config that contains the commands to run
try {
String shell = this.getProperties().getProperty(COMMAND_EXECUTE_SHELL, COMMAND_EXECUTE_SHELL_DEFAULT);
String command = this.getProperties().getProperty(COMMAND_EXECUTE_SCRIPT, null);
if (command != null && command.length() > 0) {
File dstFile = new File("script-" + UUID.randomUUID().toString());
IoUtil.fileCopy(IoUtil.getFileStream(command, log), dstFile, log);
String[] arguments = new String[]{shell, dstFile.getAbsolutePath()};
log.trace("Executing: {} {}", arguments);
Process process = Runtime.getRuntime().exec(arguments);
int exitCode = process.waitFor();
dstFile.delete();
log.debug("Finished executing command {} ({}).", command, exitCode);
}
} catch (Exception e) {
log.warn("Exception occured while trying to execute scripts", e);
return 9;
}
return 0;
}
/**
* Add Hibernate specific defaults to the base defaults
*
* @return
*/
protected static Properties getDefaultProperties() {
Properties properties = StandAloneExecutor.getDefaultProperties();
properties.setProperty(DEPLOY_DATASOURCE_CONFIGURATION, "true");
properties.setProperty("command", "update-to-latest-build");
properties.setProperty("exportSchema", "false");
return properties;
}
private static boolean getCommandExecuteEnabled(String envVarName, String propertyName, Properties props, boolean def) {
// Check JVM Command
String sysvar = System.getProperty(envVarName, null);
String prop = props.getProperty(propertyName, null);
String envvar = null;
try {
envvar = System.getenv(envVarName);
} catch (SecurityException e) {
log.warn("Error checking the System Environment", e);
}
log.debug("System => {}, Env => {}, Prop => {}", new String[]{ sysvar, envvar, prop });
if (sysvar != null && sysvar.length() > 0)
return Boolean.valueOf(sysvar);
// Check ENV Var
if (envvar != null && envvar.length() > 0)
return Boolean.valueOf(envvar);
// Check Config
if (prop != null && prop.length() > 0)
return Boolean.valueOf(prop);
return def;
}
public static class DataSourceDeploy {
// Even numbers are 'success'
public static final int SUCCESS = 0;
public static final int DATASOURCE_COPY_FAILED = 2;
public static final int DATASOURCE_CONFIGURATION_NONEXISTENT = 4;
// Odd Numbers are 'failures'
public static final int CONFIGURATION_ERROR = 1;
public static final int DEPLOY_DESTINATION_NONEXISTENT = 3;
public static final int UNCAUGHT_EXCEPTION = 5;
}
public static void main(String[] args) {
int status = 0;
Properties properties = getDefaultProperties();
if (!loadProperties(properties, args)) {
StandAloneExecutor.log.warn("Unable to find and load a configuration, proceeding with defaults. Please see the usage documentaion.");
}
StandAloneHibernateExecutor executor = new StandAloneHibernateExecutor();
executor.setProperties(properties);
try {
if (getCommandExecuteEnabled(XCHAIN_EXECUTE_ENV, XCHAIN_EXECUTE, executor.getProperties(), true)) {
log.debug("EXECUTING XCHAIN");
executor.execute();
}
else {
log.info("SKIPPING XCHAIN");
}
} catch (Exception e) {
StandAloneExecutor.log.error("There was an unexpected exception while executing the xchain", e);
status = 7;
}
// Deploy the Data source
try {
if (getCommandExecuteEnabled(DEPLOY_DATASOURCE_CONFIGURATION_ENV, DEPLOY_DATASOURCE_CONFIGURATION, executor.getProperties(), true)) {
log.debug("DEPLOYING DATASOURCE");
status = executor.deployDatasource(
executor.getProperties().getProperty(DEPLOY_LOCATION, System.getenv(DEPLOY_LOCATION_ENV)),
executor.getProperties().getProperty(DATASOURCE_CONFIGURATION, null)
);
}
else {
log.info("SKIPPING DATASOURCE");
}
} catch (Exception e) {
StandAloneExecutor.log.error("There was an unexpected exception while deploying the datasource", e);
status = 7;
}
try {
if (getCommandExecuteEnabled(COMMAND_EXECUTE_ENABLED_VAR, COMMAND_EXECUTE_ENABLED, executor.getProperties(), false)) {
log.debug("EXECUTING COMMANDS");
status = executor.runCommands();
}
else {
log.info("SKIPPING COMMANDS");
}
} catch (Exception e) {
StandAloneExecutor.log.error("There was an unexpected exception while executing scripts", e);
status = 7;
}
log.debug("Exiting with status: {}", status);
System.exit(status);
}
}