package liquibase.integration.ant.type;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.OfflineConnection;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.DataType;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.util.ClasspathUtils;
import org.apache.tools.ant.util.LoaderUtils;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;
public class DatabaseType extends DataType {
private static final String USER = "user";
private static final String PASSWORD = "password";
private String driver;
private String url;
private String user;
private String password;
private ConnectionProperties connectionProperties;
private String defaultSchemaName;
private String defaultCatalogName;
private String currentDateTimeFunction;
private boolean outputDefaultSchema = true;
private boolean outputDefaultCatalog = true;
private String liquibaseSchemaName;
private String liquibaseCatalogName;
private String databaseClass;
private String databaseChangeLogTableName;
private String databaseChangeLogLockTableName;
private String liquibaseTablespaceName;
public DatabaseType(Project project) {
setProject(project);
}
public Database createDatabase() {
ClassLoader contextClassLoader = LoaderUtils.getContextClassLoader();
return createDatabase(contextClassLoader);
}
public Database createDatabase(ClassLoader classLoader) {
logParameters();
validateParameters();
try {
DatabaseFactory databaseFactory = DatabaseFactory.getInstance();
if(databaseClass != null) {
Database databaseInstance = (Database) ClasspathUtils.newInstance(databaseClass, classLoader, Database.class);
databaseFactory.register(databaseInstance);
}
DatabaseConnection jdbcConnection;
if (getUrl().startsWith("offline:")) {
jdbcConnection = new OfflineConnection(getUrl(), new ClassLoaderResourceAccessor(classLoader));
} else {
Driver driver = (Driver) ClasspathUtils.newInstance(getDriver(), classLoader, Driver.class);
if(driver == null) {
throw new BuildException("Unable to create Liquibase Database instance. Could not instantiate the JDBC driver.");
}
Properties connectionProps = new Properties();
String user = getUser();
if(user != null && !user.isEmpty()) {
connectionProps.setProperty(USER, user);
}
String password = getPassword();
if(password != null && !password.isEmpty()) {
connectionProps.setProperty(PASSWORD, password);
}
ConnectionProperties connectionProperties = getConnectionProperties();
if(connectionProperties != null) {
connectionProps.putAll(connectionProperties.buildProperties());
}
Connection connection = driver.connect(getUrl(), connectionProps);
if(connection == null) {
throw new BuildException("Unable to create Liquibase Database instance. Could not connect to the database.");
}
jdbcConnection = new JdbcConnection(connection);
}
Database database = databaseFactory.findCorrectDatabaseImplementation(jdbcConnection);
String schemaName = getDefaultSchemaName();
if (schemaName != null) {
database.setDefaultSchemaName(schemaName);
}
String catalogName = getDefaultCatalogName();
if (catalogName != null) {
database.setDefaultCatalogName(catalogName);
}
String currentDateTimeFunction = getCurrentDateTimeFunction();
if(currentDateTimeFunction != null) {
database.setCurrentDateTimeFunction(currentDateTimeFunction);
}
database.setOutputDefaultSchema(isOutputDefaultSchema());
database.setOutputDefaultCatalog(isOutputDefaultCatalog());
String liquibaseSchemaName = getLiquibaseSchemaName();
if (liquibaseSchemaName != null) {
database.setLiquibaseSchemaName(liquibaseSchemaName);
}
String liquibaseCatalogName = getLiquibaseCatalogName();
if(liquibaseCatalogName != null) {
database.setLiquibaseCatalogName(liquibaseCatalogName);
}
String databaseChangeLogTableName = getDatabaseChangeLogTableName();
if(databaseChangeLogTableName != null) {
database.setDatabaseChangeLogTableName(databaseChangeLogTableName);
}
String databaseChangeLogLockTableName = getDatabaseChangeLogLockTableName();
if(databaseChangeLogLockTableName != null) {
database.setDatabaseChangeLogLockTableName(databaseChangeLogLockTableName);
}
String liquibaseTablespaceName = getLiquibaseTablespaceName();
if(liquibaseTablespaceName != null) {
database.setLiquibaseTablespaceName(liquibaseTablespaceName);
}
return database;
} catch (SQLException e) {
throw new BuildException("Unable to create Liquibase database instance. A JDBC error occurred. " + e.toString(), e);
} catch (DatabaseException e) {
throw new BuildException("Unable to create Liquibase database instance. " + e.toString(), e);
}
}
private void validateParameters() {
if(getUrl() == null) {
throw new BuildException("JDBC URL is required.");
}
if(getDriver() == null && !getUrl().startsWith("offline:")) {
throw new BuildException("JDBC driver is required.");
}
}
private void logParameters() {
log("Creating Liquibase Database", Project.MSG_DEBUG);
log("JDBC driver: " + driver, Project.MSG_DEBUG);
log("JDBC URL: " + url, Project.MSG_DEBUG);
log("JDBC username: " + user, Project.MSG_DEBUG);
log("Default catalog name: " + defaultCatalogName, Project.MSG_DEBUG);
log("Default schema name: " + defaultSchemaName, Project.MSG_DEBUG);
log("Liquibase catalog name: " + liquibaseCatalogName, Project.MSG_DEBUG);
log("Liquibase schema name: " + liquibaseSchemaName, Project.MSG_DEBUG);
log("Liquibase tablespace name: " + liquibaseTablespaceName, Project.MSG_DEBUG);
log("Database changelog table name: " + databaseChangeLogTableName, Project.MSG_DEBUG);
log("Database changelog lock table name: " + databaseChangeLogLockTableName, Project.MSG_DEBUG);
log("Output default catalog: " + outputDefaultCatalog, Project.MSG_DEBUG);
log("Output default schema: " + outputDefaultSchema, Project.MSG_DEBUG);
log("Current date/time function: " + currentDateTimeFunction, Project.MSG_DEBUG);
log("Database class: " + databaseClass, Project.MSG_DEBUG);
}
@Override
public void setRefid(Reference ref) {
if(driver != null
|| url != null
|| user != null
|| password != null
|| defaultSchemaName != null
|| defaultCatalogName != null
|| currentDateTimeFunction != null
|| databaseClass != null
|| liquibaseSchemaName != null
|| liquibaseCatalogName != null
|| databaseChangeLogTableName != null
|| databaseChangeLogLockTableName != null
|| liquibaseTablespaceName != null) {
throw tooManyAttributes();
}
super.setRefid(ref);
}
public String getDriver() {
return isReference() ? ((DatabaseType) getCheckedRef()).getDriver() : driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return isReference() ? ((DatabaseType) getCheckedRef()).getUrl() : url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return isReference() ? ((DatabaseType) getCheckedRef()).getUser() : user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return isReference() ? ((DatabaseType) getCheckedRef()).getPassword() : password;
}
public void setPassword(String password) {
this.password = password;
}
public ConnectionProperties getConnectionProperties() {
return isReference() ? ((DatabaseType) getCheckedRef()).getConnectionProperties() : connectionProperties;
}
public void addConnectionProperties(ConnectionProperties connectionProperties) {
if(this.connectionProperties != null) {
throw new BuildException("Only one <connectionProperties> element is allowed.");
}
this.connectionProperties = connectionProperties;
}
public String getDefaultSchemaName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getDefaultSchemaName() : defaultSchemaName;
}
public void setDefaultSchemaName(String defaultSchemaName) {
this.defaultSchemaName = defaultSchemaName;
}
public String getDefaultCatalogName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getDefaultCatalogName() : defaultCatalogName;
}
public void setDefaultCatalogName(String defaultCatalogName) {
this.defaultCatalogName = defaultCatalogName;
}
public String getCurrentDateTimeFunction() {
return isReference() ? ((DatabaseType) getCheckedRef()).getCurrentDateTimeFunction() : currentDateTimeFunction;
}
public void setCurrentDateTimeFunction(String currentDateTimeFunction) {
this.currentDateTimeFunction = currentDateTimeFunction;
}
public boolean isOutputDefaultSchema() {
return isReference() ? ((DatabaseType) getCheckedRef()).isOutputDefaultSchema() : outputDefaultSchema;
}
public void setOutputDefaultSchema(boolean outputDefaultSchema) {
this.outputDefaultSchema = outputDefaultSchema;
}
public boolean isOutputDefaultCatalog() {
return isReference() ? ((DatabaseType) getCheckedRef()).isOutputDefaultCatalog() : outputDefaultCatalog;
}
public void setOutputDefaultCatalog(boolean outputDefaultCatalog) {
this.outputDefaultCatalog = outputDefaultCatalog;
}
public String getDatabaseClass() {
return isReference() ? ((DatabaseType) getCheckedRef()).getDatabaseClass() : databaseClass;
}
public void setDatabaseClass(String databaseClass) {
this.databaseClass = databaseClass;
}
public String getLiquibaseSchemaName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getLiquibaseSchemaName() : liquibaseSchemaName;
}
public void setLiquibaseSchemaName(String liquibaseSchemaName) {
this.liquibaseSchemaName = liquibaseSchemaName;
}
public String getLiquibaseCatalogName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getLiquibaseCatalogName() : liquibaseCatalogName;
}
public void setLiquibaseCatalogName(String liquibaseCatalogName) {
this.liquibaseCatalogName = liquibaseCatalogName;
}
public String getDatabaseChangeLogTableName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getDatabaseChangeLogTableName() : databaseChangeLogTableName;
}
public void setDatabaseChangeLogTableName(String databaseChangeLogTableName) {
this.databaseChangeLogTableName = databaseChangeLogTableName;
}
public String getDatabaseChangeLogLockTableName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getDatabaseChangeLogLockTableName() : databaseChangeLogLockTableName;
}
public void setDatabaseChangeLogLockTableName(String databaseChangeLogLockTableName) {
this.databaseChangeLogLockTableName = databaseChangeLogLockTableName;
}
public String getLiquibaseTablespaceName() {
return isReference() ? ((DatabaseType) getCheckedRef()).getLiquibaseTablespaceName() : liquibaseTablespaceName;
}
public void setLiquibaseTablespaceName(String liquibaseTablespaceName) {
this.liquibaseTablespaceName = liquibaseTablespaceName;
}
}