/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.component.tool;
import java.io.File;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.component.ComponentManager;
import com.opengamma.component.ComponentRepository;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.StartupUtils;
import com.opengamma.util.db.tool.DbToolContext;
/**
* Abstract tool for operating on databases.
* <p>
* This type of tool requires a config-based database tool context in order to obtain direct access to a database.
*
* @param <T> the type of database tool context
*/
public abstract class AbstractDbTool<T extends DbToolContext> {
/**
* The logger.
*/
private static final Logger s_logger = LoggerFactory.getLogger(AbstractDbTool.class);
/**
* Help command line option.
*/
private static final String HELP_OPTION = "h";
/**
* Configuration command line option.
*/
private static final String CONFIG_RESOURCE_OPTION = "c";
/**
* Logging command line option.
*/
private static final String LOGBACK_RESOURCE_OPTION = "l";
/**
* Write command line option.
*/
private static final String WRITE_OPTION = "w";
/**
* Output file command line option.
*/
private static final String OUTPUT_FILE_OPTION = "o";
static {
StartupUtils.init();
}
/**
* The command line.
*/
private CommandLine _commandLine;
/**
* The database tool context.
*/
private T _dbToolContext;
//-------------------------------------------------------------------------
/**
* Initializes the tool statically.
*
* @param logbackResource the logback resource location, not null
* @return true if successful
*/
public static final boolean init(final String logbackResource) {
return ToolUtils.initLogback(logbackResource);
}
//-------------------------------------------------------------------------
/**
* Initializes and runs the tool from standard command-line arguments.
* <p>
* The base class defined three options:<br />
* c/config - the config file, mandatory unless default specified<br />
* l/logback - the logback configuration, default tool-logback.xml<br />
* h/help - prints the help tool<br />
*
* @param args the command-line arguments, not null
* @param toolContextClass the type of database tool context to create, should match the generic type argument
* @return true if successful, false otherwise
*/
public boolean initAndRun(String[] args, Class<? extends T> toolContextClass) {
ArgumentChecker.notNull(args, "args");
Options options = createOptions();
CommandLineParser parser = new PosixParser();
CommandLine line;
try {
line = parser.parse(options, args);
} catch (ParseException e) {
usage(options);
return false;
}
_commandLine = line;
if (line.hasOption(HELP_OPTION)) {
usage(options);
return true;
}
String logbackResource = line.getOptionValue(LOGBACK_RESOURCE_OPTION);
logbackResource = StringUtils.defaultIfEmpty(logbackResource, ToolUtils.getDefaultLogbackConfiguration());
String configResource = line.getOptionValue(CONFIG_RESOURCE_OPTION);
return init(logbackResource) && run(configResource, toolContextClass);
}
/**
* Runs the tool.
*
* @param configResource the config resource location, not null
* @param dbToolContextClass the type of database tool context to create, should match the generic type argument
* @return true if successful
*/
public final boolean run(String configResource, Class<? extends T> dbToolContextClass) {
T dbToolContext = null;
try {
ArgumentChecker.notEmpty(configResource, "configResource");
s_logger.info("Starting " + getClass().getSimpleName());
dbToolContext = initDbToolContext(configResource, dbToolContextClass);
s_logger.info("Running " + getClass().getSimpleName());
run(dbToolContext);
s_logger.info("Finished " + getClass().getSimpleName());
return true;
} catch (Exception ex) {
ex.printStackTrace();
return false;
} finally {
if (dbToolContext != null) {
dbToolContext.close();
}
}
}
/**
* Runs the tool, calling {@code doRun}.
* <p>
* This will catch not handle exceptions, but will convert checked exceptions to unchecked.
*
* @param dbToolContext the database tool context, not null
* @throws RuntimeException if an error occurs
*/
public final void run(T dbToolContext) {
_dbToolContext = dbToolContext;
try {
boolean write = getCommandLine().hasOption(WRITE_OPTION);
String outputFilePath = getCommandLine().getOptionValue(OUTPUT_FILE_OPTION);
File outputFile = outputFilePath != null ? new File(outputFilePath) : null;
doRun(write, outputFile);
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
protected static <T extends DbToolContext> T initDbToolContext(String configResource, Class<T> dbToolContextClass) {
ComponentManager manager = new ComponentManager("dbtoolcontext");
manager.start(configResource);
ComponentRepository repo = manager.getRepository();
T dbToolContext = repo.getInstance(dbToolContextClass, "tool");
if (dbToolContext == null) {
throw new OpenGammaRuntimeException("Unable to find tool context in config resource");
}
return dbToolContext;
}
//-------------------------------------------------------------------------
/**
* Override in subclasses to implement the tool.
*
* @param write true to modify the database, false to output the commands that would be run
* @param outputFile the file to which the SQL should be written, null not to write to a file
*
* @throws Exception if an error occurs
*/
protected abstract void doRun(boolean write, File outputFile) throws Exception;
//-------------------------------------------------------------------------
/**
* Gets the database tool context.
*
* @return the context, not null during {@code doRun}
*/
protected T getDbToolContext() {
return _dbToolContext;
}
/**
* Gets the parsed command line.
*
* @return the parsed command line, not null after parsing
*/
protected CommandLine getCommandLine() {
return _commandLine;
}
//-------------------------------------------------------------------------
/**
* Creates the command line options.
* <p>
* Subclasses may override this and add their own parameters. The base class defined the options h/help, c/config, l/logback.
*
* @return the set of command line options, not null
*/
protected Options createOptions() {
Options options = new Options();
options.addOption(createHelpOption());
options.addOption(createConfigOption());
options.addOption(createLogbackOption());
options.addOption(createWriteOption());
options.addOption(createOutputFileOption());
return options;
}
private static Option createHelpOption() {
return new Option(HELP_OPTION, "help", false, "prints this message");
}
private static Option createConfigOption() {
Option option = new Option(CONFIG_RESOURCE_OPTION, "config", true, "the database tool context configuration resource");
option.setArgName("resource");
option.setRequired(true);
return option;
}
private static Option createLogbackOption() {
Option option = new Option(LOGBACK_RESOURCE_OPTION, "logback", true, "the logback configuration resource");
option.setArgName("resource");
option.setRequired(false);
return option;
}
private static Option createWriteOption() {
return new Option(WRITE_OPTION, "write", false, "whether to modify the database");
}
private static Option createOutputFileOption() {
Option option = new Option(OUTPUT_FILE_OPTION, "output", true, "a file to which the SQL should be output");
option.setArgName("file");
option.setRequired(false);
return option;
}
protected void usage(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.setWidth(120);
formatter.printHelp("java " + getClass().getName(), options, true);
}
}