Package org.jboss.seam.wiki.util

Source Code of org.jboss.seam.wiki.util.DBUnitImporter$DataSetOperation

package org.jboss.seam.wiki.util;

import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.DataTypeException;
import org.dbunit.dataset.datatype.DefaultDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.operation.DatabaseOperation;

import javax.naming.InitialContext;
import javax.sql.DataSource;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

/**
* Imports some data into the database with the help of DBUnit. This allows us to
* use the same dataset files as in unit testing, but in the regular application startup during
* development. Also helps to avoid maintaining the crude Hibernate import.sql file.
*
* @author Christian Bauer
*/
public class DBUnitImporter {

    public enum Database {
        hsql, mysql, postgresql
    }

    protected Database database;

    private String datasourceJndiName;

    String binaryDir;

    List<String> datasets = new ArrayList<String>();

    public void setDatabase(String database) {
        this.database = Database.valueOf(database);
    }

    public String getDatasourceJndiName() {
        return datasourceJndiName;
    }

    public void setDatasourceJndiName(String datasourceJndiName) {
        this.datasourceJndiName = datasourceJndiName;
    }

    public String getBinaryDir() {
        return binaryDir;
    }

    public void setBinaryDir(String binaryDir) {
        this.binaryDir = binaryDir;
    }

    public List<String> getDatasets() {
        return datasets;
    }

    public void setDatasets(List<String> datasets) {
        this.datasets = datasets;
    }

    public void importDatasets() throws Exception {

        List<DataSetOperation> dataSetOperations = new ArrayList<DataSetOperation>();

        for (String dataset : datasets) {
            dataSetOperations.add(new DataSetOperation(dataset));
        }

        IDatabaseConnection con = null;
        try {
            con = getConnection();
            disableReferentialIntegrity(con);
            for (DataSetOperation op : dataSetOperations) {
                prepareExecution(con, op);
                op.execute(con);
                afterExecution(con, op);
            }
            enableReferentialIntegrity(con);
        } finally {
            if (con != null) {
                try {
                    con.close();
                } catch (Exception ex) {
                    ex.printStackTrace(System.err);
                }
            }
        }

    }

    /**
     * Override this method if you want to provide your own DBUnit <tt>IDatabaseConnection</tt> instance.
     * <p/>
     * If you do not override this, default behavior is to use the * configured datasource name and
     * to obtain a connection with a JNDI lookup.
     *
     * @return a DBUnit database connection (wrapped)
     */
    protected IDatabaseConnection getConnection() {
        try {
            DataSource datasource = ((DataSource)new InitialContext().lookup(datasourceJndiName));

            // Get a JDBC connection from JNDI datasource
            Connection con = datasource.getConnection();
            IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
            editConfig(dbUnitCon.getConfig());
            return dbUnitCon;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Override this method if you aren't using HSQL DB.
     * <p/>
     * Execute whatever statement is necessary to either defer or disable foreign
     * key constraint checking on the given database connection, which is used by
     * DBUnit to import datasets.
     *
     * @param con A DBUnit connection wrapper, which is used afterwards for dataset operations
     */
    protected void disableReferentialIntegrity(IDatabaseConnection con) {
        try {
            if (database.equals(Database.hsql)) {
                con.getConnection().prepareStatement("set referential_integrity FALSE").execute(); // HSQL DB
            } else if (database.equals(Database.mysql)) {
                con.getConnection().prepareStatement("set foreign_key_checks=0").execute(); // MySQL > 4.1.1
            } else if (database.equals(Database.postgresql)) {
                // See prepareExecution() and afterExecution()
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Override this method if you aren't using HSQL DB.
     * <p/>
     * Execute whatever statement is necessary to enable integrity constraint checks after
     * dataset operations.
     *
     * @param con A DBUnit connection wrapper, before it is used by the application again
     */
    protected void enableReferentialIntegrity(IDatabaseConnection con) {
        try {
            if (database.equals(Database.hsql)) {
                con.getConnection().prepareStatement("set referential_integrity TRUE").execute()// HSQL DB
            } else if (database.equals(Database.mysql)) {
                con.getConnection().prepareStatement("set foreign_key_checks=1").execute(); // MySQL > 4.1.1
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Override this method if you require DBUnit configuration features or additional properties.
     * <p>
     * Called after a connection has been obtaind and before the connection is used. Can be a
     * NOOP method if no additional settings are necessary for your DBUnit/DBMS setup.
     *
     * @param config A DBUnit <tt>DatabaseConfig</tt> object for setting properties and features
     */
    protected void editConfig(DatabaseConfig config) {

        if (database.equals(Database.hsql)) {
            // DBUnit/HSQL bugfix
            // http://www.carbonfive.com/community/archives/2005/07/dbunit_hsql_and.html
            config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new DefaultDataTypeFactory() {
                public DataType createDataType(int sqlType, String sqlTypeName)
                  throws DataTypeException {
                   if (sqlType == Types.BOOLEAN) {
                      return DataType.BOOLEAN;
                    }
                   return super.createDataType(sqlType, sqlTypeName);
                 }
            });
        }

    }

    /**
     * Resolves the binary dir location with the help of the classloader, we need the
     * absolute full path of that directory.
     *
     * @return String full absolute path of the binary directory
     */
    protected String getBinaryDirFullpath() {
        if (binaryDir == null) {
            throw new RuntimeException("Please set binaryDir property to location of binary test files");
        }
        URL url = Thread.currentThread().getContextClassLoader().getResource(getBinaryDir());
        if (url == null) {
            throw new RuntimeException("Could not find full path with classloader of binaryDir: " + getBinaryDir());
        }
        return url.toString();
    }

    /**
     * Callback for each operation, useful if extra preparation of data/tables is necessary.
     *
     * @param con A DBUnit connection wrapper
     * @param operation The operation to be executed, call <tt>getDataSet()</tt> to access the data.
     */
    protected void prepareExecution(IDatabaseConnection con, DataSetOperation operation) {
        try {
            // PostgreSQL has no global switch to turn off foreign key checks, needs to be toggled on each table
            if (database.equals(Database.postgresql)) {
                for (String tableName : operation.getDataSet().getTableNames()) {
                    con.getConnection().prepareStatement("alter table " + tableName + " disable trigger all").execute();
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Callback for each operation, useful if extra preparation of data/tables is necessary.
     *
     * @param con A DBUnit connection wrapper
     * @param operation The operation that was executed, call <tt>getDataSet()</tt> to access the data.
     */
    protected void afterExecution(IDatabaseConnection con, DataSetOperation operation) {
        try {
            // PostgreSQL has no global switch to turn off foreign key checks, needs to be toggled on each table
            if (database.equals(Database.postgresql)) {
                for (String tableName : operation.getDataSet().getTableNames()) {
                    con.getConnection().prepareStatement("alter table " + tableName + " enable trigger all").execute();
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    protected class DataSetOperation {
        String dataSetLocation;
        ReplacementDataSet dataSet;
        DatabaseOperation operation;

        /**
         * Defaults to <tt>DatabaseOperation.CLEAN_INSERT</tt>
         */
        public DataSetOperation(String dataSetLocation){
            this(dataSetLocation, DatabaseOperation.INSERT);
        }

        public DataSetOperation(String dataSetLocation, DatabaseOperation operation) {
            // Load the base dataset file
            InputStream input = Thread.currentThread().getContextClassLoader().getResourceAsStream(dataSetLocation);
            try {
                this.dataSet = new ReplacementDataSet( new FlatXmlDataSet(input) );
            } catch (Exception ex) {
                throw new RuntimeException("Could not load dataset for import: " + dataSetLocation, ex);
            }
            this.dataSet.addReplacementObject("[NULL]", null);
            this.dataSet.addReplacementSubstring("[BINARY_DIR]", getBinaryDirFullpath());
            this.operation = operation;
            this.dataSetLocation = dataSetLocation;
        }

        public IDataSet getDataSet() {
            return dataSet;
        }

        public DatabaseOperation getOperation() {
            return operation;
        }

        public void execute(IDatabaseConnection connection) {
            try {
                this.operation.execute(connection, dataSet);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }

        public String toString() {
            // TODO: This is not pretty because DBUnit's DatabaseOperation doesn't implement toString() properly
            return operation.getClass() + " with dataset: " + dataSetLocation;
        }
    }

}
TOP

Related Classes of org.jboss.seam.wiki.util.DBUnitImporter$DataSetOperation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.