All Downloads are FREE. Search and download functionalities are using the official Maven repository.

liquibase.integration.ant.BaseLiquibaseTask Maven / Gradle / Ivy

There is a newer version: 4.30.0
Show newest version
package liquibase.integration.ant;

import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.logging.LogFactory;
import liquibase.logging.Logger;
import liquibase.resource.CompositeResourceAccessor;
import liquibase.resource.FileSystemResourceAccessor;
import liquibase.resource.ResourceAccessor;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.Connection;
import java.sql.Driver;
import java.util.*;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

/**
 * Base class for all Ant Liquibase tasks.  This class sets up Liquibase and defines parameters
 * that are common to all tasks.
 */
public class BaseLiquibaseTask extends Task {
    private String changeLogFile;
    private String driver;
    private String url;
    private String username;
    private String password;
    protected Path classpath;
    private boolean promptOnNonLocalDatabase = false;
    private String currentDateTimeFunction;
    private String contexts;
    private String outputFile;
    private String defaultSchemaName;
    private String databaseClass;
    private String databaseChangeLogTableName;
    private String databaseChangeLogLockTableName;


    private Map changeLogProperties = new HashMap();

    public BaseLiquibaseTask() {
        super();
        new LogRedirector(this).redirectLogger();
    }

    @Override
    public void execute() throws BuildException {
        super.execute();

        AntClassLoader loader = getProject().createClassLoader(classpath);
        loader.setParent(this.getClass().getClassLoader());
        loader.setThreadContextLoader();

    }

    public boolean isPromptOnNonLocalDatabase() {
        return promptOnNonLocalDatabase;
    }

    public void setPromptOnNonLocalDatabase(boolean promptOnNonLocalDatabase) {
        this.promptOnNonLocalDatabase = promptOnNonLocalDatabase;
    }

    public String getDriver() {
        return driver;
    }

    public void setDriver(String driver) {
        this.driver = driver.trim();
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url.trim();
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username.trim();
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password.trim();
    }

    public String getChangeLogFile() {
        return changeLogFile;
    }

    public void setChangeLogFile(String changeLogFile) {
        this.changeLogFile = changeLogFile.trim();
    }

    public Path createClasspath() {
        if (this.classpath == null) {
            this.classpath = new Path(getProject());
        }
        return this.classpath.createPath();
    }

    public void setClasspathRef(Reference r) {
        createClasspath().setRefid(r);
    }

    public String getCurrentDateTimeFunction() {
        return currentDateTimeFunction;
    }

    public void setCurrentDateTimeFunction(String currentDateTimeFunction) {
        this.currentDateTimeFunction = currentDateTimeFunction.trim();
    }

    public String getOutputFile() {
        return outputFile;
    }

    public void setOutputFile(String outputFile) {
        this.outputFile = outputFile.trim();
    }

    public Writer createOutputWriter() throws IOException {
        if (outputFile == null) {
            return null;
        }
        return new FileWriter(new File(getOutputFile()));
    }

    public PrintStream createPrintStream() throws IOException {
        if (outputFile == null) {
            return null;
        }
        return new PrintStream(new File(getOutputFile()));
    }

    public String getDefaultSchemaName() {
        return defaultSchemaName;
    }

    public void setDefaultSchemaName(String defaultSchemaName) {
        this.defaultSchemaName = defaultSchemaName.trim();
    }

    public void addConfiguredChangeLogProperty(ChangeLogProperty changeLogProperty) {
        changeLogProperties.put(changeLogProperty.getName(), changeLogProperty.getValue());
    }

    protected Liquibase createLiquibase() throws Exception {
        ResourceAccessor antFO = new AntResourceAccessor(getProject(), classpath);
        ResourceAccessor fsFO = new FileSystemResourceAccessor();

        Database database = createDatabaseObject(getDriver(), getUrl(), getUsername(), getPassword(), getDefaultSchemaName(), getDatabaseClass());

        String changeLogFile = null;
        if (getChangeLogFile() != null) {
            changeLogFile = getChangeLogFile().trim();
        }
        Liquibase liquibase = new Liquibase(changeLogFile, new CompositeResourceAccessor(antFO, fsFO), database);
        liquibase.setCurrentDateTimeFunction(currentDateTimeFunction);
        for (Map.Entry entry : changeLogProperties.entrySet()) {
            liquibase.setChangeLogParameter(entry.getKey(), entry.getValue());
        }

        return liquibase;
    }

    protected Database createDatabaseObject(String driverClassName,
                                            String databaseUrl,
                                            String username,
                                            String password,
                                            String defaultSchemaName,
                                            String databaseClass) throws Exception {
        String[] strings = classpath.list();

        final List taskClassPath = new ArrayList();
        for (String string : strings) {
            URL url = new File(string).toURL();
            taskClassPath.add(url);
        }

        URLClassLoader loader = AccessController.doPrivileged(new PrivilegedAction() {
            public URLClassLoader run() {
                return new URLClassLoader(taskClassPath.toArray(new URL[taskClassPath.size()]), Database.class.getClassLoader());
            }
        });

        Database database;


        if (databaseClass != null) {
            try {
                DatabaseFactory.getInstance().register((Database) Class.forName(databaseClass, true, loader).newInstance());
            } catch (ClassCastException e) { //fails in Ant in particular
                DatabaseFactory.getInstance().register((Database) Class.forName(databaseClass).newInstance());
            }
        }

        if (driverClassName == null) {
            driverClassName = DatabaseFactory.getInstance().findDefaultDriver(databaseUrl);
        }

        if (driverClassName == null) {
            throw new DatabaseException("driver not specified and no default could be found for " + databaseUrl);
        }

        Driver driver = (Driver) Class.forName(driverClassName, true, loader).newInstance();

        Properties info = new Properties();
        if (username != null) {
            info.put("user", username);
        }
        if (password != null) {
            info.put("password", password);
        }
        Connection connection = driver.connect(databaseUrl, info);

        if (connection == null) {
            throw new DatabaseException("Connection could not be created to " + databaseUrl + " with driver " + driver.getClass().getName() + ".  Possibly the wrong driver for the given database URL");
        }

        database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
        database.setDefaultSchemaName(defaultSchemaName);

        if (getDatabaseChangeLogTableName() != null)
            database.setDatabaseChangeLogTableName(getDatabaseChangeLogTableName());

        if (getDatabaseChangeLogLockTableName() != null)
            database.setDatabaseChangeLogLockTableName(getDatabaseChangeLogLockTableName());

        return database;
    }

    public String getContexts() {
        return contexts;
    }

    public void setContexts(String cntx) {
        this.contexts = cntx.trim();
    }


    /**
     * Redirector of logs from java.util.logging to ANT's loggging
     */
    protected static class LogRedirector {

        private final Task task;

        /**
         * Constructor
         *
         * @param task
         */
        protected LogRedirector(Task task) {
            super();
            this.task = task;
        }

        protected void redirectLogger() {
            registerHandler(createHandler());
        }

        protected void registerHandler(Handler theHandler) {
            Logger logger = LogFactory.getLogger();
        }


        protected Handler createHandler() {
            return new Handler() {
                @Override
                public void publish(LogRecord logRecord) {
                    task.log(logRecord.getMessage(), mapLevelToAntLevel(logRecord.getLevel()));
                }

                @Override
                public void close() throws SecurityException {
                }

                @Override
                public void flush() {
                }

                protected int mapLevelToAntLevel(Level level) {
                    if (Level.ALL == level) {
                        return Project.MSG_INFO;
                    } else if (Level.SEVERE == level) {
                        return Project.MSG_ERR;
                    } else if (Level.WARNING == level) {
                        return Project.MSG_WARN;
                    } else if (Level.INFO == level) {
                        return Project.MSG_INFO;
                    } else {
                        return Project.MSG_VERBOSE;
                    }
                }
            };
        }

    }

    protected boolean shouldRun() {
        String shouldRunProperty = System.getProperty(Liquibase.SHOULD_RUN_SYSTEM_PROPERTY);
        if (shouldRunProperty != null && !Boolean.valueOf(shouldRunProperty)) {
            log("Liquibase did not run because '" + Liquibase.SHOULD_RUN_SYSTEM_PROPERTY + "' system property was set to false");
            return false;
        }
        return true;
    }

    protected void closeDatabase(Liquibase liquibase) {
        if (liquibase != null && liquibase.getDatabase() != null && liquibase.getDatabase().getConnection() != null) {
            try {
                liquibase.getDatabase().close();
            } catch (DatabaseException e) {
                log("Error closing database: " + e.getMessage());
            }
        }
    }

    public String getDatabaseClass() {
        return databaseClass;
    }

    public void setDatabaseClass(String databaseClass) {
        this.databaseClass = databaseClass;
    }

    public String getDatabaseChangeLogTableName() {
        return databaseChangeLogTableName;
    }


    public void setDatabaseChangeLogTableName(String tableName) {
        this.databaseChangeLogTableName = tableName;
    }


    public String getDatabaseChangeLogLockTableName() {
        return databaseChangeLogLockTableName;
    }


    public void setDatabaseChangeLogLockTableName(String tableName) {
        this.databaseChangeLogLockTableName = tableName;
    }

    public String getLogLevel() {
        return LogFactory.getLogger().getLogLevel().name();
    }

    public void setLogLevel(String level) {
        LogFactory.getLogger().setLogLevel(level);
    }

    public static class ChangeLogProperty {
        private String name;
        private String value;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy