uk.ac.ebi.bioinvindex.utils.test.DBUnitTest.java Source code

Java tutorial

Introduction

Here is the source code for uk.ac.ebi.bioinvindex.utils.test.DBUnitTest.java

Source

package uk.ac.ebi.bioinvindex.utils.test;

/*
 * __________
 * CREDITS
 * __________
 *
 * Team page: http://isatab.sf.net/
 * - Marco Brandizi (software engineer: ISAvalidator, ISAconverter, BII data management utility, BII model)
 * - Eamonn Maguire (software engineer: ISAcreator, ISAcreator configurator, ISAvalidator, ISAconverter,  BII data management utility, BII web)
 * - Nataliya Sklyar (software engineer: BII web application, BII model,  BII data management utility)
 * - Philippe Rocca-Serra (technical coordinator: user requirements and standards compliance for ISA software, ISA-tab format specification, BII model, ISAcreator wizard, ontology)
 * - Susanna-Assunta Sansone (coordinator: ISA infrastructure design, standards compliance, ISA-tab format specification, BII model, funds raising)
 *
 * Contributors:
 * - Manon Delahaye (ISA team trainee:  BII web services)
 * - Richard Evans (ISA team trainee: rISAtab)
 *
 *
 * ______________________
 * Contacts and Feedback:
 * ______________________
 *
 * Project overview: http://isatab.sourceforge.net/
 *
 * To follow general discussion: isatab-devel@list.sourceforge.net
 * To contact the developers: isatools@googlegroups.com
 *
 * To report bugs: http://sourceforge.net/tracker/?group_id=215183&atid=1032649
 * To request enhancements:  http://sourceforge.net/tracker/?group_id=215183&atid=1032652
 *
 *
 * __________
 * License:
 * __________
 *
 * This work is licenced under the Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License. To view a copy of this licence, visit http://creativecommons.org/licenses/by-sa/2.0/uk/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.
 *
 * __________
 * Sponsors
 * __________
 * This work has been funded mainly by the EU Carcinogenomics (http://www.carcinogenomics.eu) [PL 037712] and in part by the
 * EU NuGO [NoE 503630](http://www.nugo.org/everyone) projects and in part by EMBL-EBI.
 */

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dbunit.DatabaseUnitException;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.DefaultDataSet;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.LowerCaseDataSet;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.datatype.DefaultDataTypeFactory;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.dbunit.ext.oracle.Oracle10DataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
import org.hibernate.Session;
import org.junit.After;
import org.junit.Before;

import uk.ac.ebi.bioinvindex.utils.test.H2DataTypeFactory;

/**
 * Base class used to make test classes which uses the database and Hibernate peristence.
 *
 * User: Nataliya Sklyar (nsklyar@ebi.ac.uk), Review by brandizi, Ago 2008
 * Date: Sep 10, 2007
 */
public abstract class DBUnitTest {

    protected static List<DatabaseOperation> beforeTestOperations = new ArrayList<DatabaseOperation>();
    protected static List<DatabaseOperation> afterTestOperations = new ArrayList<DatabaseOperation>();
    protected EntityManagerFactory entityManagerFactory;
    protected EntityManager entityManager;
    protected Session session;
    protected Connection connection;
    protected IDatabaseConnection dbunitConnection;

    protected String dataSetLocation;

    protected final static Logger log = Logger.getLogger(DBUnitTest.class);

    /**
     * Calls {@link #init()}
     *
     * @throws Exception
     */
    protected DBUnitTest() throws Exception {
        init();
    }

    /**
     * specify {@link #dataSetLocation}, {@link #beforeTestOperations}, {@value #afterTestOperations}.
     * The default is:
     *
     * <pre>
     *    beforeTestOperations.add ( DatabaseOperation.CLEAN_INSERT );
     *    dataSetLocation = "study-data.xml";
     * </pre>
     */
    protected void prepareSettings() {
        beforeTestOperations.add(DatabaseOperation.CLEAN_INSERT);
        dataSetLocation = "study-data.xml";
    }

    /**
     * Initializes the class for doing a test. This default calls {@link #prepareSettings()} {@link #initEntityManager()},
     *
     * @throws Exception
     */
    protected void init() throws Exception {
        prepareSettings();
        initEntityManager(true);
    }

    /**
     * Runs {@link #initDataSet()} before every test.
     * 
     */
    @Before
    public void beforeTestProcessing() throws Exception {
        initDataSet();
        // cleanAll ();
    }

    /**
     * By default Performs the operations in {@link #afterTestOperations} and closes connection/session/entityManager.
     *
     */
    @After
    public void afterTestProcessing() throws Exception {
        if (afterTestOperations == null || afterTestOperations.size() == 0)
            return;

        // TODO: Problems when have we Hibernate and committed transactions
        setReferentialIntegrityCheckings(false);
        IDatabaseConnection dbUnitCon = createDbUnitConnection();

        IDataSet dset = getDataSet();
        try {
            for (DatabaseOperation op : afterTestOperations) {
                op.execute(dbUnitCon, dset);
            }
        } finally {
            setReferentialIntegrityCheckings(true);
            connection.close();
        }
        session.flush();
        close();
    }

    /**
     * Closes the EntityManager.
     *
     * @throws Exception
     */
    protected void close() {
        // if ( entityManager.isOpen () ) entityManager.close();
        if (entityManagerFactory.isOpen())
            entityManagerFactory.close();
    }

    /**
     * Loads an XML data-set, used by {@link #initDataSet()}.
     *
     */
    protected IDataSet getDataSet() throws DataSetException, IOException {
        if (dataSetLocation == null) {
            System.out.println("*** WARNING: Test subclass should prepare a dataset location");
            return new DefaultDataSet();
        }

        InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(dataSetLocation);

        IDataSet dataSet = new FlatXmlDataSet(input);

        // This allows to specify [null] for null values
        ReplacementDataSet repDs = new ReplacementDataSet(dataSet);
        repDs.addReplacementObject("[null]", null);

        // Converts only column names to lower case (required in MySQL).
        return new LowerCaseDataSet(repDs) {
            @Override
            public boolean isCaseSensitiveTableNames() {
                return true;
            }
        };

    }

    /**
     * A facility to clean all the tables in the database, independently on the fact they appear or not in the dataset.
     *
     * TODO: Not completely sure it works with Oracle... :-\
     *
     * @throws SQLException
     */
    protected void cleanAll() throws SQLException {
        setReferentialIntegrityCheckings(false);

        try {
            Statement delstmt = connection.createStatement();
            DatabaseMetaData dbmsMeta = connection.getMetaData();
            String dbmsName = dbmsMeta.getDatabaseProductName().toLowerCase();
            String dbmsCatalog = connection.getCatalog();
            if (dbmsCatalog == null)
                // Let's try with the user name
                dbmsCatalog = dbmsMeta.getUserName().toUpperCase();

            String dbmsSchema = null;
            if (dbmsName.contains("oracle")) {
                // The damn Oracle needs the schema in getTables(), otherwise it returns undeletable
                // system tables too.
                //
                Statement stmt = connection.createStatement();
                ResultSet rs = stmt
                        .executeQuery("select sys_context('USERENV', 'CURRENT_SCHEMA') CURRENT_SCHEMA from dual");
                if (rs.next())
                    dbmsSchema = rs.getString(1);
                stmt.close();
            }

            log.debug("DBMSUnitTest.cleanAll(), DBMS Name: '" + dbmsName + "' Catalog: '" + dbmsCatalog
                    + "' Schema: '" + dbmsSchema + "'");

            ResultSet tbrs = dbmsMeta.getTables(dbmsCatalog, dbmsSchema, null, new String[] { "TABLE" });

            while (tbrs.next()) {
                String tbname = StringUtils.trimToNull(tbrs.getString("TABLE_NAME"));
                if (tbname == null)
                    continue;
                // Oracle system tables
                String sql = "DROP TABLE " + tbname;
                if (!dbmsName.contains("mysql"))
                    sql += " CASCADE CONSTRAINTS";
                log.debug("DBUnitTest, adding sql: " + sql);
                delstmt.addBatch(sql);
            }
            delstmt.executeBatch();
        } finally {
            setReferentialIntegrityCheckings(true);
            connection.close();
            // All tables were deleted, we need this to force schema recreation.
            initEntityManager(true);
        }
    }

    /**
     * Inits several variables used by this class.
     *
     * @param forceRecreation when false, objects are not reinitialized if they are non null.
     *
     */
    protected void initEntityManager(boolean forceRecreation) {
        if (forceRecreation && entityManager != null)
            close();
        if (forceRecreation || entityManagerFactory == null)
            entityManagerFactory = Persistence.createEntityManagerFactory("BIIEntityManager");
        if (forceRecreation || entityManager == null)
            entityManager = entityManagerFactory.createEntityManager();
        if (forceRecreation || session == null)
            session = (Session) entityManager.getDelegate();
        if (forceRecreation || connection == null)
            connection = session.connection();
    }

    /**
     * Defaults to {@link #initEntityManager(boolean) initConnection(false)}
     *
     */
    protected void initEntityManager() {
        initEntityManager(false);
    }

    /**
     * Enables/disables the referential integrity checkings in the database.
     *
     * @param isset
     * @throws SQLException
     */
    protected void setReferentialIntegrityCheckings(boolean isset) throws SQLException {

        String sql = null;

        DatabaseMetaData dbmsMeta = connection.getMetaData();
        String dbmsName = dbmsMeta.getDatabaseProductName().toLowerCase();
        String dbmsCatalog = connection.getCatalog();
        if (dbmsCatalog == null)
            // Let's try with the user name
            dbmsCatalog = dbmsMeta.getUserName().toUpperCase();

        log.debug("DBUnitTest.setReferentialIntegrityCheckings(), DBMS Name: '" + dbmsName + "' Catalog: '"
                + dbmsCatalog + "'");

        if (dbmsName.contains("h2"))
            sql = "SET REFERENTIAL_INTEGRITY " + isset;
        else if (dbmsName.contains("mysql"))
            sql = "set FOREIGN_KEY_CHECKS = " + (isset ? "1" : "0");
        else if (dbmsName.contains("oracle")) {
            // Oracle is quite messy...
            String sqlCs = "select css.*, decode(CONSTRAINT_TYPE, 'P', '0', 'C', '1', 'U', 2, 'R', '3', 1000) ctype "
                    + "from sys.all_constraints css where owner = '" + dbmsCatalog + "' order by ctype "
                    + (isset ? "ASC" : "DESC");

            ResultSet rs = connection.createStatement().executeQuery(sqlCs);
            Statement csDelStmt = connection.createStatement();
            while (rs.next()) {
                String sqlCsCmd = isset ? "enable" : "disable";
                String tbname = rs.getString("TABLE_NAME");
                String csname = rs.getString("CONSTRAINT_NAME");

                String sqlCsDel = "alter table " + dbmsCatalog + "." + tbname + " " + sqlCsCmd + " constraint "
                        + csname;
                log.debug("DBUnitTest, adding sql: " + sqlCsDel);
                csDelStmt.addBatch(sqlCsDel);
            }
            csDelStmt.executeBatch();
            return;
        }

        if (sql == null)
            throw new SQLException(
                    "Don't know how to change referential integrity checks for the database: '" + dbmsName + "'");

        connection.createStatement().execute(sql);
    }

    /**
     * Initializes the database with data-set and operations returned by {@link #getDataSet()}.
     *
     */
    protected void initDataSet() throws SQLException, DataSetException, DatabaseUnitException, IOException {
        if (beforeTestOperations == null || beforeTestOperations.size() == 0)
            return;

        setReferentialIntegrityCheckings(false);
        IDatabaseConnection dbUnitCon = createDbUnitConnection();

        IDataSet dset = getDataSet();
        try {
            for (DatabaseOperation op : beforeTestOperations) {
                op.execute(dbUnitCon, dset);
            }
        } finally {
            setReferentialIntegrityCheckings(true);
            connection.close();
        }
        session.flush();
    }

    /**
     * Creates a new database connection to be used by DbUnit, used {@link #initDataSet()} and {@link #afterTestProcessing()}.
     * @throws SQLException 
     *
     */
    protected IDatabaseConnection createDbUnitConnection() throws SQLException, DatabaseUnitException {
        IDatabaseConnection dbUnitCon = new DatabaseConnection(connection);
        DatabaseConfig config = dbUnitCon.getConfig();

        DatabaseMetaData dbmsMeta = connection.getMetaData();
        String dbmsName = dbmsMeta.getDatabaseProductName().toLowerCase();
        String dbmsCatalog = connection.getCatalog();
        if (dbmsCatalog == null)
            // Let's try with the user name
            dbmsCatalog = dbmsMeta.getUserName().toUpperCase();

        IDataTypeFactory dtf = new DefaultDataTypeFactory();
        if (dbmsName.contains("h2"))
            dtf = new H2DataTypeFactory();
        else if (dbmsName.contains("mysql"))
            dtf = new MySqlDataTypeFactory();
        else if (dbmsName.contains("oracle"))
            dtf = new Oracle10DataTypeFactory();
        else
            System.out.println("WARNING: Don't know which DBUnit DataType factory to use with '" + dbmsName
                    + ", hope the default works");

        config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, dtf);

        return dbUnitCon;
    }
}