/*
* Copyright 2016 Hortonworks.
*
* 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 com.hortonworks.registries.storage.tool;
import org.apache.commons.cli.BasicParser;
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.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.BooleanUtils;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Scanner;
public class TablesInitializer {
private static final String OPTION_SCRIPT_ROOT_PATH = "script-root";
private static final String OPTION_CONFIG_FILE_PATH = "config";
private static final String OPTION_MYSQL_JAR_URL_PATH = "mysql-jar-url";
private static final String OPTION_EXECUTE_CREATE_TABLE = "create";
private static final String OPTION_EXECUTE_DROP_TABLE = "drop";
private static final String OPTION_EXECUTE_CHECK_CONNECTION = "check-connection";
private static final String CREATE_SCRIPT_FILE_NAME = "create_tables.sql";
private static final String DROP_SCRIPT_FILE_NAME = "drop_tables.sql";
public static void main(String[] args) throws Exception {
Options options = new Options();
options.addOption(
Option.builder("s")
.numberOfArgs(1)
.longOpt(OPTION_SCRIPT_ROOT_PATH)
.desc("Root directory of script path")
.build()
);
options.addOption(
Option.builder("c")
.numberOfArgs(1)
.longOpt(OPTION_CONFIG_FILE_PATH)
.desc("Config file path")
.build()
);
options.addOption(
Option.builder("m")
.numberOfArgs(1)
.longOpt(OPTION_MYSQL_JAR_URL_PATH)
.desc("Mysql client jar url to download")
.build()
);
options.addOption(
Option.builder()
.hasArg(false)
.longOpt(OPTION_EXECUTE_CREATE_TABLE)
.desc("Execute 'create table' script")
.build()
);
options.addOption(
Option.builder()
.hasArg(false)
.longOpt(OPTION_EXECUTE_DROP_TABLE)
.desc("Execute 'drop table' script")
.build()
);
options.addOption(
Option.builder()
.hasArg(false)
.longOpt(OPTION_EXECUTE_CHECK_CONNECTION)
.desc("Check the connection for configured data source")
.build()
);
CommandLineParser parser = new BasicParser();
CommandLine commandLine = parser.parse(options, args);
if (!commandLine.hasOption(OPTION_CONFIG_FILE_PATH) || !commandLine.hasOption(OPTION_SCRIPT_ROOT_PATH)) {
usage(options);
System.exit(1);
}
// either create or drop should be specified, not both
boolean executeCreate = commandLine.hasOption(OPTION_EXECUTE_CREATE_TABLE);
boolean executeDrop = commandLine.hasOption(OPTION_EXECUTE_DROP_TABLE);
boolean checkConnection = commandLine.hasOption(OPTION_EXECUTE_CHECK_CONNECTION);
boolean moreThanOneOperationIsSpecified = executeCreate == executeDrop ? executeCreate : checkConnection;
boolean noOperationSpecified = !(executeCreate || executeDrop || checkConnection);
if (moreThanOneOperationIsSpecified) {
System.out.println("Only one operation can be execute at once, please select 'create' or 'drop', or 'check-connection'.");
System.exit(1);
} else if (noOperationSpecified) {
System.out.println("One of 'create', 'drop', 'check-connection' operation should be specified to execute.");
System.exit(1);
}
String confFilePath = commandLine.getOptionValue(OPTION_CONFIG_FILE_PATH);
String scriptRootPath = commandLine.getOptionValue(OPTION_SCRIPT_ROOT_PATH);
String mysqlJarUrl = commandLine.getOptionValue(OPTION_MYSQL_JAR_URL_PATH);
StorageProviderConfiguration storageProperties;
try {
Map<String, Object> conf = Utils.readConfig(confFilePath);
StorageProviderConfigurationReader confReader = new StorageProviderConfigurationReader();
storageProperties = confReader.readStorageConfig(conf);
} catch (IOException e) {
System.err.println("Error occurred while reading config file: " + confFilePath);
System.exit(1);
throw new IllegalStateException("Shouldn't reach here");
}
String bootstrapDirPath = null;
try {
bootstrapDirPath = System.getProperty("bootstrap.dir");
MySqlDriverHelper.downloadMySQLJarIfNeeded(storageProperties, bootstrapDirPath, mysqlJarUrl);
} catch (Exception e) {
System.err.println("Error occurred while downloading MySQL jar. bootstrap dir: " + bootstrapDirPath);
System.exit(1);
throw new IllegalStateException("Shouldn't reach here");
}
try {
SQLScriptRunner sqlScriptRunner = new SQLScriptRunner(storageProperties);
try {
sqlScriptRunner.initializeDriver();
} catch (ClassNotFoundException e) {
System.err.println("Driver class is not found in classpath. Please ensure that driver is in classpath.");
System.exit(1);
}
if (checkConnection) {
if (!sqlScriptRunner.checkConnection()) {
System.exit(1);
}
} else if (executeDrop) {
doExecuteDrop(sqlScriptRunner, storageProperties, scriptRootPath);
} else {
// executeCreate
doExecuteCreate(sqlScriptRunner, storageProperties, scriptRootPath);
}
} catch (IOException e) {
System.err.println("Error occurred while reading script file. Script root path: " + scriptRootPath);
System.exit(1);
}
}
private static void doExecuteCreate(SQLScriptRunner sqlScriptRunner, StorageProviderConfiguration storageProperties,
String scriptRootPath) throws Exception {
String scriptPath = scriptRootPath + File.separator + storageProperties.getDbType() +
File.separator + CREATE_SCRIPT_FILE_NAME;
doExecute(sqlScriptRunner, scriptPath);
}
private static void doExecuteDrop(SQLScriptRunner sqlScriptRunner, StorageProviderConfiguration storageProperties,
String scriptRootPath) throws Exception {
System.out.println("The operation will drop any existing tables.");
System.out.print("Are you sure you want to proceed. (y/n)?");
Scanner scan = new Scanner(System.in);
String line = scan.nextLine();
System.out.println();
Boolean proceed = BooleanUtils.toBooleanObject(line);
if (!BooleanUtils.toBoolean(proceed)) {
System.exit(0);
}
String scriptPath = scriptRootPath + File.separator + storageProperties.getDbType() +
File.separator + DROP_SCRIPT_FILE_NAME;
doExecute(sqlScriptRunner, scriptPath);
}
private static void doExecute(SQLScriptRunner sqlScriptRunner, String scriptPath) throws Exception {
sqlScriptRunner.runScript(scriptPath);
}
private static Option option(int argCount, String shortName, String longName, String description){
return option(argCount, shortName, longName, longName, description);
}
private static Option option(int argCount, String shortName, String longName, String argName, String description){
return OptionBuilder.hasArgs(argCount)
.withArgName(argName)
.withLongOpt(longName)
.withDescription(description)
.create(shortName);
}
private static void usage(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("Registry TableInitializer [options]", options);
}
}