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

de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils.LiquibaseHelper Maven / Gradle / Ivy

There is a newer version: 2.5.0
Show newest version
/*
 * Copyright (C) 2018 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
 * Karlsruhe, Germany.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */
package de.fraunhofer.iosb.ilt.frostserver.persistence.pgjooq.utils;

import de.fraunhofer.iosb.ilt.frostserver.util.exception.UpgradeFailedException;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import liquibase.Contexts;
import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.DatabaseException;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper functions for Liquibase.
 *
 * @author scf
 */
public class LiquibaseHelper {

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

    private LiquibaseHelper() {
        // Utility class, should not be instantiated.
    }

    public static String checkForUpgrades(Connection connection, String liquibaseChangelogFilename, Map params) {
        StringWriter out = new StringWriter();
        try {
            Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
            runLiquibaseCheck(liquibaseChangelogFilename, params, database, out);
        } catch (DatabaseException ex) {
            outputError(ex, out, "Failed to initialise database");
        }
        return out.toString();
    }

    public static boolean doUpgrades(Connection connection, String liquibaseChangelogFilename, Map params, Writer out) throws UpgradeFailedException, IOException {
        try {
            runLiquibaseUpdate(liquibaseChangelogFilename, params, connection, out);
        } catch (DatabaseException ex) {
            outputError(ex, out, "Failed to initialise database");
            return false;
        }
        return true;
    }

    private static void runLiquibaseCheck(String liquibaseChangelogFilename, Map params, Database database, StringWriter out) {
        try (Liquibase liquibase = new Liquibase(liquibaseChangelogFilename, new ClassLoaderResourceAccessor(), database)) {
            for (Map.Entry entry : params.entrySet()) {
                liquibase.setChangeLogParameter(entry.getKey(), entry.getValue());
            }
            liquibase.update(new Contexts(), out);
        } catch (LiquibaseException ex) {
            outputError(ex, out, "Failed to upgrade database");
        } catch (Exception ex) {
            LOGGER.warn("Exception happened when closing liquibase.", ex);
        }
    }

    private static void runLiquibaseUpdate(String liquibaseChangelogFilename, Map params, Connection connection, Writer out) throws UpgradeFailedException, IOException, DatabaseException {
        Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
        try (Liquibase liquibase = new Liquibase(liquibaseChangelogFilename, new ClassLoaderResourceAccessor(), database)) {
            String searchPath = getSearchPath(connection);

            for (Map.Entry entry : params.entrySet()) {
                liquibase.setChangeLogParameter(entry.getKey(), entry.getValue());
            }
            liquibase.update(new Contexts());

            setSearchPath(connection, searchPath);
        } catch (LiquibaseException ex) {
            outputError(ex, out, "Failed to upgrade database");
            throw new UpgradeFailedException(ex);
        } catch (Exception ex) {
            LOGGER.warn("Exception happened when closing liquibase.", ex);
        }
    }

    private static String getSearchPath(Connection connection) {
        try (PreparedStatement call = connection.prepareStatement("show search_path")) {
            call.execute();
            try (ResultSet resultSet = call.getResultSet()) {
                if (resultSet.next()) {
                    final String searchPath = resultSet.getString(1);
                    LOGGER.debug("Found search_path: {}", searchPath);
                    return searchPath;
                }
            }
        } catch (SQLException ex) {
            LOGGER.error("Failed to fetch search_path: ", ex);
        }
        return "";
    }

    private static void setSearchPath(Connection connection, String wantedSearchPath) {
        String searchPath = getSearchPath(connection);
        if (wantedSearchPath.equals(searchPath)) {
            return;
        }
        LOGGER.info("Liquibase changed the search_path from '{}' to '{}'. Changing it back.", wantedSearchPath, searchPath);
        try (PreparedStatement call = connection.prepareStatement("select set_config('search_path', ?, false)")) {
            call.setString(1, wantedSearchPath);
            call.execute();
            connection.commit();
        } catch (SQLException ex) {
            LOGGER.error("Failed to set search_path: ", ex);
        }
    }

    private static void outputError(final Exception exception, final StringWriter out, final String message) {
        try {
            outputError(exception, (Writer) out, message);
        } catch (IOException exc) {
            LOGGER.error("Error writing output.", exc);
            // Never happens.
        }
    }

    private static void outputError(final Exception exception, final Writer out, final String message) throws IOException {
        LOGGER.error(message, exception);
        out.append(message + ":\n");
        out.append(exception.getLocalizedMessage());
        out.append("\n");
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy