/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* 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
*
* 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.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.framework.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
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.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.mifos.db.upgrade.DatabaseUpgradeSupport;
import org.mifos.framework.ApplicationInitializer;
import org.mifos.framework.hibernate.helper.StaticHibernateUtil;
import org.mifos.framework.persistence.SqlExecutor;
import org.mifos.framework.util.helpers.FilePaths;
import org.mifos.service.test.TestingService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.Log4jConfigurer;
public class DataSetUpgradeUtil {
// Command line flag configuration.
private static final String DATA_SET_OPTION_NAME = "f";
private static final String DATA_DIRECTORY_OPTION_NAME = "a";
private static final String USER_OPTION_NAME = "u";
private static final String PASSWORD_OPTION_NAME = "p";
private static final String PORT_OPTION_NAME = "P";
private static final String HELP_OPTION_NAME = "h";
private static final String DATABASE_OPTION_NAME = "d";
private static final String SCHEMA_FILE_OPTION_NAME = "s";
// Options
private final Options options = new Options();
private Option outputFile;
private Option userOption;
private Option passwordOption;
private Option helpOption;
private Option databaseOption;
private Option allFilesInDirecoryOption;
private Option schemaFileOption;
private Option portOption;
// Variables for data from command line
String dataSetName;
String databaseName = "mifos_gazelle_acceptance";
String user;
String password = "";
String dataSetDirectoryName;
String schemaFileName = "base_schema.sql";
String port = "3306";
DbUnitUtilities dbUnitUtilities;
public static void main(String[] args) throws Exception {
Log4jConfigurer.initLogging(new ConfigurationLocator().getFilePath(FilePaths.LOG_CONFIGURATION_FILE));
DataSetUpgradeUtil util = new DataSetUpgradeUtil();
util.doUpgrades(args);
}
public DataSetUpgradeUtil() {
defineOptions();
}
public void doUpgrades(String[] args) throws Exception {
parseOptions(args);
System.out.println("Using database: " + databaseName);
System.out.println("Using schema file: " + schemaFileName);
ApplicationContext applicationContext = initializeSpring();
if (dataSetDirectoryName != null) {
File directory = new File(dataSetDirectoryName);
File[] listOfFiles = directory.listFiles();
if (listOfFiles != null) {
int totalFilesToUpgrade = countFilesToUpgrade(listOfFiles);
int filesUpgraded = 0;
for (File listOfFile : listOfFiles) {
String currentFilename = listOfFile.getName();
if (listOfFile.isFile() && currentFilename.endsWith("dbunit.xml")) {
String dataFileName = dataSetDirectoryName + File.separator + currentFilename;
upgrade(dataFileName, applicationContext);
dump(dataFileName);
filesUpgraded++;
System.out.println("Finished " + filesUpgraded + "/" + totalFilesToUpgrade);
}
}
} else {
fail("No files found in data set directory: " + dataSetDirectoryName);
}
} else {
upgrade(dataSetName, applicationContext);
dump(dataSetName);
}
}
private int countFilesToUpgrade(File[] listOfFiles) {
int fileCount = 0;
for (File listOfFile : listOfFiles) {
String currentFilename = listOfFile.getName();
if (listOfFile.isFile() && currentFilename.endsWith("dbunit.xml")) {
++fileCount;
}
}
return fileCount;
}
private void resetDatabase(String databaseName, Connection connection) throws SQLException {
Statement statement = connection.createStatement();
try {
statement.execute("DROP DATABASE IF EXISTS " + databaseName);
statement.execute("CREATE DATABASE " + databaseName);
statement.execute("USE " + databaseName);
} finally {
statement.close();
}
}
private void upgrade(String fileName, ApplicationContext applicationContext) throws Exception {
System.out.println("Upgrading: " + fileName);
dbUnitUtilities = new DbUnitUtilities();
IDataSet dataSet = null;
try {
dataSet = dbUnitUtilities.getDataSetFromFile(fileName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Class.forName("com.mysql.jdbc.Driver");
Connection jdbcConnection = null;
try {
// TODO use same db cxn info that Mifos uses! (local.properties)
jdbcConnection = DriverManager.getConnection(getUrl(databaseName, port, params), user, password);
jdbcConnection.setAutoCommit(false);
resetDatabase(databaseName, jdbcConnection);
SqlExecutor.execute(new FileInputStream(schemaFileName), jdbcConnection);
jdbcConnection.commit();
jdbcConnection.setAutoCommit(true);
IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnection);
databaseConnection.getConfig()
.setProperty(DatabaseConfig.FEATURE_CASE_SENSITIVE_TABLE_NAMES, Boolean.FALSE);
DatabaseOperation.CLEAN_INSERT.execute(databaseConnection, dataSet);
} finally {
if (jdbcConnection != null) {
jdbcConnection.close();
}
}
System.setProperty(TestingService.TEST_MODE_SYSTEM_PROPERTY, "acceptance");
ApplicationInitializer applicationInitializer = new ApplicationInitializer();
applicationInitializer.dbUpgrade(applicationContext);
applicationContext.getBean(DatabaseUpgradeSupport.class).contraction();
applicationInitializer.setAttributesOnContext(null);
StaticHibernateUtil.closeSession();
System.out.println(" upgrade done!");
}
public static ApplicationContext initializeSpring() {
return new ClassPathXmlApplicationContext("classpath:/org/mifos/config/resources/applicationContext.xml",
"classpath:META-INF/spring/DbUpgradeContext.xml", "classpath:META-INF/spring/CashFlowContext.xml",
"classpath:META-INF/spring/QuestionnaireContext.xml");
}
private static final String params = "?sessionVariables=FOREIGN_KEY_CHECKS=0";
private String getUrl(String databaseName, String port, String params) {
return String.format("jdbc:mysql://localhost:%s/%s%s", port, databaseName, params);
}
// Rationale: jdbcConnection is closed.
private void dump(String fileName) throws ClassNotFoundException, SQLException, DatabaseUnitException, IOException {
System.out.println("Dumping :" + fileName);
Connection jdbcConnection = DriverManager.getConnection(getUrl(databaseName, port, params), user, password);
String fileEnding = fileName.substring(fileName.length() - 3, fileName.length());
if ("xml".equals(fileEnding)) {
// dump xml
dbUnitUtilities.dumpDatabase(fileName, jdbcConnection);
} else if ("sql".equals(fileEnding)) {
// dump sql
fail("ERROR: SQL dumping not implemented yet. Please dump " + databaseName
+ " manually with mysqldump. The upgrades have been applied.");
} else {
fail("ERROR: Bad data set name. The file ending has to be .xml or .sql");
}
jdbcConnection.close();
System.out.println(" dump done!");
}
@SuppressWarnings("static-access")
private void defineOptions() {
outputFile = OptionBuilder
.withArgName("data set file name")
.withLongOpt("dataset")
.hasArg()
.withDescription(
"Upgrade the test data set with this name-- include the full file path (e.g. /home/me/dataSets/data_dbunit.xml")
.create(DATA_SET_OPTION_NAME);
allFilesInDirecoryOption = OptionBuilder
.withArgName("data set directory")
.withLongOpt("dataDirectory")
.hasArg()
.withDescription(
"Upgrade all test data sets in this directory-- include the full path (e.g. /home/me/dataSets )")
.create(DATA_DIRECTORY_OPTION_NAME);
userOption = OptionBuilder.withArgName("user name").withLongOpt("user").hasArg()
.withDescription("database user name").create(USER_OPTION_NAME);
passwordOption = OptionBuilder.withArgName("password").withLongOpt("password").hasArg()
.withDescription("database password").create(PASSWORD_OPTION_NAME);
databaseOption = OptionBuilder
.withArgName("database")
.withLongOpt("database")
.hasArg()
.withDescription(
"database name (default=" + databaseName
+ ") this must match whatever acceptance.database points to in local.properties")
.create(DATABASE_OPTION_NAME);
schemaFileOption = OptionBuilder.withArgName("schema file").withLongOpt("schema").hasArg()
.withDescription("schema file to upgrade from (default=" + schemaFileName + ")")
.create(SCHEMA_FILE_OPTION_NAME);
portOption = OptionBuilder.withArgName("port").withLongOpt("port").hasArg()
.withDescription("mysql server port (default=" + port + ")").create(PORT_OPTION_NAME);
helpOption = OptionBuilder.withLongOpt("help").withDescription("display help").create(HELP_OPTION_NAME);
options.addOption(outputFile);
options.addOption(userOption);
options.addOption(passwordOption);
options.addOption(helpOption);
options.addOption(databaseOption);
options.addOption(allFilesInDirecoryOption);
options.addOption(schemaFileOption);
options.addOption(portOption);
}
public void parseOptions(String[] args) throws URISyntaxException {
// create the command line parser
CommandLineParser parser = new PosixParser();
try {
// parse the command line arguments
CommandLine line = parser.parse(options, args);
if (line.hasOption(HELP_OPTION_NAME)) {
showHelp(options);
System.exit(0);
}
if (line.hasOption(DATA_SET_OPTION_NAME)) {
if (line.hasOption(DATA_DIRECTORY_OPTION_NAME)) {
fail("Specify either a data set (-f) or data directory (-a) but not both.");
}
dataSetName = line.getOptionValue(DATA_SET_OPTION_NAME);
} else if (line.hasOption(DATA_DIRECTORY_OPTION_NAME)) {
dataSetDirectoryName = line.getOptionValue(DATA_DIRECTORY_OPTION_NAME);
} else {
fail("Specify either a data set (-f) or data directory (-a)");
}
if (line.hasOption(USER_OPTION_NAME)) {
user = line.getOptionValue(USER_OPTION_NAME);
} else {
missingOption(userOption);
}
if (line.hasOption(PASSWORD_OPTION_NAME)) {
password = line.getOptionValue(PASSWORD_OPTION_NAME);
}
if (line.hasOption(DATABASE_OPTION_NAME)) {
databaseName = line.getOptionValue(DATABASE_OPTION_NAME);
}
if (line.hasOption(SCHEMA_FILE_OPTION_NAME)) {
schemaFileName = line.getOptionValue(SCHEMA_FILE_OPTION_NAME);
File file = new File(schemaFileName);
if (!file.exists()) {
fail("Unable to find schema file: " + schemaFileName);
}
} else {
missingOption(schemaFileOption);
}
if (line.hasOption(PORT_OPTION_NAME)) {
port = line.getOptionValue(PORT_OPTION_NAME);
}
} catch (ParseException exp) {
fail("Parsing failed. Reason: " + exp.getMessage());
}
}
private static void showHelp(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("DbUnitDataExport", options);
}
private static void missingOption(Option option) {
fail("Missing required option: " + option.getArgName());
}
private static void fail(String string) {
System.err.println(string);
System.exit(0);
}
}