/*
*
* Copyright (c) 2013 - 2017 Lijun Liao
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation with the addition of the
* following permission added to Section 15 as permitted in Section 7(a):
*
* FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
* THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
* OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the XiPKI software without
* disclosing the source code of your own applications.
*
* For more information, please contact Lijun Liao at this
* address: lijun.liao@gmail.com
*/
package org.xipki.commons.dbtool;
import java.util.Objects;
import liquibase.CatalogAndSchema;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.diff.compare.CompareControl;
import liquibase.diff.output.DiffOutputControl;
import liquibase.exception.CommandLineParsingException;
import liquibase.exception.DatabaseException;
import liquibase.integration.commandline.CommandLineResourceAccessor;
import liquibase.integration.commandline.CommandLineUtils;
import liquibase.lockservice.LockService;
import liquibase.lockservice.LockServiceFactory;
import liquibase.logging.LogFactory;
import liquibase.logging.Logger;
import liquibase.resource.CompositeResourceAccessor;
import liquibase.resource.FileSystemResourceAccessor;
import liquibase.resource.ResourceAccessor;
/**
* Class for executing Liquibase via the command line.
*
* @author Lijun Liao
* @since 2.0.0
*/
public class LiquibaseMain {
private final LiquibaseDatabaseConf dbConf;
private final String changeLogFile;
private Database database;
private Liquibase liquibase;
public LiquibaseMain(final LiquibaseDatabaseConf dbConf, final String changeLogFile) {
Objects.requireNonNull(dbConf, "dbConf must not be null");
if (changeLogFile == null || changeLogFile.isEmpty()) {
throw new IllegalArgumentException("changeLogFile must not be empty");
}
this.dbConf = dbConf;
this.changeLogFile = changeLogFile;
}
public void changeLogLevel(final String logLevel, String logFile)
throws CommandLineParsingException {
Objects.requireNonNull(logLevel, "logLevel must not be null");
try {
Logger log = LogFactory.getInstance().getLog();
if (logFile != null && logFile.length() > 0) {
log.setLogLevel(logLevel, logFile);
} else {
log.setLogLevel(logLevel);
}
} catch (IllegalArgumentException ex) {
throw new CommandLineParsingException(ex.getMessage(), ex);
}
}
public void init(final String logLevel, String logFile) throws Exception {
changeLogLevel(logLevel, logFile);
FileSystemResourceAccessor fsOpener = new FileSystemResourceAccessor();
ClassLoader classLoader = getClass().getClassLoader();
ResourceAccessor clOpener = new CommandLineResourceAccessor(classLoader);
String defaultSchemaName = dbConf.getSchema();
this.database = CommandLineUtils.createDatabaseObject(
clOpener, // resourceAccessor
dbConf.getUrl(), // url
dbConf.getUsername(), // username
dbConf.getPassword(), // password
dbConf.getDriver(), // driver
(String) null, // defaultCatalogName
defaultSchemaName, // defaultSchemaName
false, // outputDefaultCatalog
false, // outputDefaultSchema
(String) null, // databaseClass
(String) null, // driverPropertiesFile
(String) null, // propertyProviderClass
(String) null, // liquibaseCatalogName
(String) null, // liquibaseSchemaName
(String) null, // databaseChangeLogTableName
(String) null); // databaseChangeLogLockTableName
try {
CompositeResourceAccessor fileOpener = new CompositeResourceAccessor(fsOpener,
clOpener);
DiffOutputControl diffOutputControl = new DiffOutputControl(false, // includeCatalog
false, // includeSchema
false, // includeTablespace
null); // schemaComparisons
CompareControl.SchemaComparison[] finalSchemaComparisons;
finalSchemaComparisons = new CompareControl.SchemaComparison[] {
new CompareControl.SchemaComparison(new CatalogAndSchema(null, defaultSchemaName),
new CatalogAndSchema(null, defaultSchemaName))};
for (CompareControl.SchemaComparison schema : finalSchemaComparisons) {
diffOutputControl.addIncludedSchema(schema.getReferenceSchema());
diffOutputControl.addIncludedSchema(schema.getComparisonSchema());
}
this.liquibase = new Liquibase(changeLogFile, fileOpener, database);
} catch (Exception ex) {
try {
database.rollback();
database.close();
} catch (Exception e2) {
LogFactory.getInstance().getLog().warning("problem closing connection", ex);
}
throw ex;
}
} // method init
public void releaseLocks() throws Exception {
LockService lockService = LockServiceFactory.getInstance().getLockService(database);
lockService.forceReleaseLock();
System.out.println("successfully released the database");
}
public void dropAll() throws Exception {
liquibase.dropAll();
System.out.println("successfully dropped the database");
}
public void update() throws Exception {
liquibase.update((String) null);
System.out.println("successfully updated the database");
}
public void shutdown() {
try {
if (database != null) {
database.rollback();
database.close();
}
} catch (DatabaseException ex) {
LogFactory.getInstance().getLog().warning("problem closing connection", ex);
} finally {
database = null;
liquibase = null;
}
}
public static boolean loglevelIsSevereOrOff(final String logLevel) {
return "off".equalsIgnoreCase(logLevel) || "severe".equalsIgnoreCase(logLevel);
}
}