org.openmrs.util.databasechange.DatabaseUpgradeTestUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.util.databasechange.DatabaseUpgradeTestUtil.java

Source

/**
 * This Source Code Form is subject to the terms of the Mozilla Public License,
 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
 * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
 * the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
 *
 * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
 * graphic logo is a trademark of OpenMRS Inc.
 */
package org.openmrs.util.databasechange;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import liquibase.Liquibase;
import liquibase.database.Database;
import liquibase.database.DatabaseFactory;
import liquibase.database.jvm.JdbcConnection;
import liquibase.exception.LiquibaseException;
import liquibase.resource.ClassLoaderResourceAccessor;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.ext.h2.H2DataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;

/**
 * Allows to test database upgrade. It accepts initialDatabasePath which should point to the h2
 * liqubaseConnection that will be used for upgrade.
 */
public class DatabaseUpgradeTestUtil {

    private final Connection connection;

    private final Database liqubaseConnection;

    private final DatabaseConnection dbUnitConnection;

    private final File tempDir;

    private final File tempDBFile;

    private final String connectionUrl;

    public DatabaseUpgradeTestUtil(String initialDatabasePath) throws IOException, SQLException {
        InputStream databaseInputStream = getClass().getResourceAsStream(initialDatabasePath);

        tempDir = File.createTempFile("openmrs-tests-temp-", "");
        tempDir.delete();
        tempDir.mkdir();
        tempDir.deleteOnExit();

        tempDBFile = new File(tempDir, "openmrs.h2.db");
        tempDBFile.delete();
        try {
            tempDBFile.createNewFile();
        } catch (IOException e) {
            tempDir.delete();
            throw e;
        }
        tempDBFile.deleteOnExit();

        FileOutputStream tempDBOutputStream = new FileOutputStream(tempDBFile);

        try {
            IOUtils.copy(databaseInputStream, tempDBOutputStream);

            databaseInputStream.close();
            tempDBOutputStream.close();
        } catch (IOException e) {
            tempDBFile.delete();
            tempDir.delete();

            throw e;
        } finally {
            IOUtils.closeQuietly(databaseInputStream);
            IOUtils.closeQuietly(tempDBOutputStream);
        }

        String databaseUrl = tempDir.getAbsolutePath().replace("\\", "/") + "/openmrs";

        connectionUrl = "jdbc:h2:" + databaseUrl + ";AUTO_RECONNECT=TRUE;DB_CLOSE_DELAY=-1";

        connection = DriverManager.getConnection(connectionUrl, "sa", "sa");
        connection.setAutoCommit(true);

        try {
            liqubaseConnection = DatabaseFactory.getInstance()
                    .findCorrectDatabaseImplementation(new JdbcConnection(connection));
            liqubaseConnection.setDatabaseChangeLogTableName("LIQUIBASECHANGELOG");
            liqubaseConnection.setDatabaseChangeLogLockTableName("LIQUIBASECHANGELOGLOCK");
        } catch (LiquibaseException e) {
            tempDir.delete();
            tempDBFile.delete();

            throw new SQLException(e);
        }

        try {
            dbUnitConnection = new DatabaseConnection(connection);
            dbUnitConnection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
                    new H2DataTypeFactory());
        } catch (DatabaseUnitException e) {
            tempDir.delete();
            tempDBFile.delete();

            throw new SQLException(e);
        }
    }

    public void close() throws SQLException {
        try {
            connection.close();
        } finally {
            tempDBFile.delete();
            tempDir.delete();
        }
    }

    public Connection getConnection() {
        return connection;
    }

    public void executeDataset(String path) throws IOException, SQLException {
        InputStream inputStream = getClass().getResourceAsStream(path);
        ReplacementDataSet replacementDataSet = null;
        try {
            replacementDataSet = new ReplacementDataSet(
                    new FlatXmlDataSet(new InputStreamReader(inputStream), false, true, false));

            inputStream.close();
        } catch (DataSetException e) {
            throw new IOException(e);
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
        replacementDataSet.addReplacementObject("[NULL]", null);

        try {
            DatabaseOperation.REFRESH.execute(dbUnitConnection, replacementDataSet);

            connection.commit();
        } catch (DatabaseUnitException e) {
            throw new IOException(e);
        }
    }

    public List<Map<String, String>> select(String tableName, String where, String columnName,
            String... columnNames) throws SQLException {
        String[] allColumnNames = ArrayUtils.addAll(new String[] { columnName }, columnNames);

        String sql = "select " + StringUtils.join(allColumnNames, ", ") + " from " + tableName;
        if (!StringUtils.isBlank(where)) {
            sql += " where " + where;
        }
        PreparedStatement query = connection.prepareStatement(sql);
        ResultSet resultSet = query.executeQuery();

        List<Map<String, String>> results = new ArrayList<Map<String, String>>();
        while (resultSet.next()) {
            Map<String, String> columns = new HashMap<String, String>();
            results.add(columns);

            for (int i = 0; i < allColumnNames.length; i++) {
                Object object = resultSet.getObject(i + 1);
                columns.put(allColumnNames[i], object != null ? object.toString() : null);
            }
        }

        query.close();

        return results;
    }

    public void insertGlobalProperty(String globalProperty, String value) throws SQLException {
        PreparedStatement insert = connection
                .prepareStatement("insert into global_property (property, property_value, uuid) values (?, ?, ?)");
        insert.setString(1, globalProperty);
        insert.setString(2, value);
        insert.setString(3, UUID.randomUUID().toString());

        insert.executeUpdate();

        insert.close();

        connection.commit();
    }

    public void upgrade() throws IOException, SQLException {
        try {
            Liquibase liquibase = new Liquibase("liquibase-update-to-latest.xml",
                    new ClassLoaderResourceAccessor(getClass().getClassLoader()), liqubaseConnection);
            liquibase.update(null);

            connection.commit();
        } catch (LiquibaseException e) {
            throw new IOException(e);
        }
    }

    public SessionFactory buildSessionFactory() {
        Configuration config = new Configuration().configure();
        //H2 version we use behaves differently from H2Dialect in Hibernate so we provide our implementation
        config.setProperty(Environment.DIALECT, H2LessStrictDialect.class.getName());
        config.setProperty(Environment.URL, connectionUrl);
        config.setProperty(Environment.DRIVER, "org.h2.Driver");
        config.setProperty(Environment.USER, "sa");
        config.setProperty(Environment.PASS, "sa");
        config.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
        config.setProperty(Environment.USE_QUERY_CACHE, "false");

        //Let's validate HBMs against the actual schema
        config.setProperty(Environment.HBM2DDL_AUTO, "validate");

        return config.buildSessionFactory();
    }
}