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

io.bootique.jdbc.liquibase.LiquibaseRunner Maven / Gradle / Ivy

/*
 * Licensed to ObjectStyle LLC under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ObjectStyle LLC licenses
 * this file to you 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 io.bootique.jdbc.liquibase;

import io.bootique.resource.ResourceFactory;
import liquibase.ContextExpression;
import liquibase.LabelExpression;
import liquibase.Liquibase;
import liquibase.changelog.ChangeLogParameters;
import liquibase.changelog.DatabaseChangeLog;
import liquibase.database.Database;
import liquibase.database.DatabaseConnection;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ResourceAccessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @since 2.0
 */
public class LiquibaseRunner {

    private static final Logger LOGGER = LoggerFactory.getLogger(LiquibaseRunner.class);

    protected Collection changeLogs;
    protected DataSource dataSource;
    protected String defaultSchema;

    public LiquibaseRunner(Collection changeLogs, DataSource dataSource, String defaultSchema) {
        this.changeLogs = Objects.requireNonNull(changeLogs);
        this.dataSource = Objects.requireNonNull(dataSource);
        this.defaultSchema = defaultSchema;
    }

    public  T call(Function op) {

        Liquibase lb = createLiquibase();
        try {
            return op.apply(lb);
        } finally {
            closeLiquibase(lb);
        }
    }

    public void run(Consumer op) {

        Liquibase lb = createLiquibase();
        try {
            op.accept(lb);
        } finally {
            closeLiquibase(lb);
        }
    }

    protected Liquibase createLiquibase() {
        ResourceAccessor resourceAccessor = new ResourceFactoryAccessor();

        try {
            Database liquibaseDB = createDatabase(dataSource.getConnection());
            DatabaseChangeLog changeLog = createDatabaseChangeLog(liquibaseDB, resourceAccessor);
            return new Liquibase(changeLog, resourceAccessor, liquibaseDB);
        } catch (SQLException | LiquibaseException e) {
            throw new RuntimeException("Error creating liquibase", e);
        }
    }

    protected DatabaseChangeLog createDatabaseChangeLog(Database database, ResourceAccessor resourceAccessor) {
        DatabaseChangeLog changeLog = new DatabaseChangeLog();
        changeLog.setChangeLogParameters(new ChangeLogParameters(database));

        // TODO: do something useful with this?
        LabelExpression labelExpression = new LabelExpression();

        changeLogs.forEach(cl -> {
            try {
                LOGGER.info("Including change log: '{}'", cl.getResourceId());
                changeLog.include(cl.getResourceId(), false, resourceAccessor, new ContextExpression(), labelExpression, false, true);
            } catch (LiquibaseException e) {
                throw new RuntimeException("Error configuring Liquibase", e);
            }
        });

        return changeLog;
    }

    protected Database createDatabase(Connection c) throws DatabaseException {

        DatabaseConnection liquibaseConnection = new JdbcConnection(c);
        DatabaseFactory databaseFactory = DatabaseFactory.getInstance();

        // Custom Derby DB to prevent Derby shutdown by Liquibase. Liquibase operates with Bootique-provided DataSource
        // and should not attempt to manage the underlying DB state.
        databaseFactory.register(new NonClosingDerbyDatabase());

        Database database = databaseFactory.findCorrectDatabaseImplementation(liquibaseConnection);

        if (defaultSchema != null) {
            database.setDefaultSchemaName(defaultSchema);
        }

        return database;
    }

    protected void closeLiquibase(Liquibase lb) {
        if (lb.getDatabase() != null) {
            try {
                lb.getDatabase().close();
            } catch (DatabaseException e) {
                LOGGER.info("Error closing Liquibase, ignored", e);
            }
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy