Package com.softwaremill.common.dbtest

Source Code of com.softwaremill.common.dbtest.TransactionalDBTest

package com.softwaremill.common.dbtest;

import bitronix.tm.BitronixTransactionManager;
import bitronix.tm.TransactionManagerServices;
import bitronix.tm.resource.jdbc.PoolingDataSource;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.h2.jdbcx.JdbcDataSource;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.ejb.AvailableSettings;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.transaction.BTMTransactionManagerLookup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import com.softwaremill.common.arquillian.BetterArquillian;
import com.softwaremill.common.cdi.persistence.EntityManagerFactoryProducer;
import com.softwaremill.common.dbtest.util.DbMode;
import com.softwaremill.common.util.dependency.BeanManagerDependencyProvider;
import com.softwaremill.common.util.dependency.D;

import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.transaction.Status;
import java.util.Properties;

/**
* Allows to create fully integration test with real transactions
* Take a look on TestTransactionalDBTest
*/
public abstract class TransactionalDBTest extends BetterArquillian {

    private static final Logger LOG = LoggerFactory.getLogger(TransactionalDBTest.class);

    /**
     * Used to configure Transaction Manager
     *
     * - bitronix.uniqueName - name to be used with JNDI to identify given Transaction Manager
     * - bitronix.file - full path to the Bitronix Transaction Manager configuration file
     *                  follow the link for more details
     *                  http://docs.codehaus.org/display/BTM/Configuration2x
     */
    protected static final String BITRONIX_UNIQUE_NAME = "bitronix.uniqueName";
    protected static final String BITRONIX_FILE = "bitronix.file";

    private static final String BITRONIX_DATASOURCE_CLASS = "bitronix.datasource.class";
    private static final String BITRONIX_CONNECTION_USERNAME = "bitronix.connection.username";
    private static final String BITRONIX_CONNECTION_URL = "bitronix.connection.url";

    protected EntityManagerFactory emf;

    @Inject
    private BeanManager bm;

    private BeanManagerDependencyProvider depProvider;
    private UtxDependencyProvider utxProvider;

    @BeforeSuite
    public void beforeSuite() throws Exception {
        setupLog4J();
        callBeforeSuite();
    }

    @AfterSuite
    public void afterSuite() throws Exception {
        callAfterSuite();
    }

    @BeforeClass
    public void beforeClass() throws Exception {
        callBeforeClass();

        Ejb3Configuration cfg = new Ejb3Configuration();
        configureTransactionManager(cfg);
        initTransactionManager(cfg);
        configureDatabase(cfg);
        configureEntities(cfg);
        emf = cfg.buildEntityManagerFactory();
        // Setting the EMF so that it's produced correctly
        EntityManagerFactoryProducer.setStaticEntityManagerFactory(emf);

        initTestData();
    }

    protected void initTransactionManager(Ejb3Configuration cfg) throws Exception{
        String configurationFile = getConfigurationFile();
        if (configurationFile != null) {
            LOG.info("Using [{}] as a configuration file for Bitronix Transaction Manager!", configurationFile);
            TransactionManagerServices.getConfiguration().setResourceConfigurationFilename(configurationFile);
        } else {
            // create InMemory H2 database
            PoolingDataSource xa = new PoolingDataSource();
            xa.setUniqueName(cfg.getProperties().getProperty(BITRONIX_UNIQUE_NAME, "test-" + getClass().getSimpleName()));
            xa.setClassName(cfg.getProperties().getProperty(BITRONIX_DATASOURCE_CLASS, JdbcDataSource.class.getName()));
            xa.setAllowLocalTransactions(true);
            xa.setMaxPoolSize(3);
            xa.setMinPoolSize(1);

            Properties prop = new Properties();
            String url = cfg.getProperties().getProperty(BITRONIX_CONNECTION_URL, "jdbc:h2:mem:" + getClass().getSimpleName());
            if (compatibilityMode() != null) {
                url += ";MODE=" + compatibilityMode();
            }
            prop.setProperty("URL", url);
            prop.setProperty("user", cfg.getProperties().getProperty(BITRONIX_CONNECTION_USERNAME, "sa"));

            xa.setDriverProperties(prop);
            xa.init();

            TransactionManagerServices.getResourceLoader().getResources().put(xa.getUniqueName(), xa);
        }
        TransactionManagerServices.getResourceLoader().init();
    }

    protected String getConfigurationFile() throws Exception {
        return null;
    }

    protected void initTestData() throws Exception {
        EntityManager em = emf.createEntityManager();
        loadTestData(em);
    }

    @AfterClass
    public void afterClass() throws Exception {
        callAfterClass();

        shutdownEmf();
        shutdownTransactionManager();
        D.unregister(depProvider);
        D.unregister(utxProvider);
    }

    @BeforeMethod
    public void beforeMethod() throws Exception {
        callBeforeMethod();
        registerBeanManager();
        registerUtxProvider();
    }

    protected void registerUtxProvider() {
        if (utxProvider == null) {
            utxProvider = new UtxDependencyProvider();
            D.register(utxProvider);
        }
    }

    protected void registerBeanManager() {
        if (depProvider == null) {
            depProvider = new BeanManagerDependencyProvider(bm);
            D.register(depProvider);
        }
    }

    @AfterMethod
    public void afterMethod() throws Exception {
        callAfterMethod();
    }

    /**
     * Override to setup test on BeforeSuite
     */
    protected void callBeforeSuite() throws Exception {
    }

    /**
     * Override to tear down test on AfterSuite
     */
    protected void callAfterSuite() throws Exception {
    }

    /**
     * Override to setup test on BeforeClass
     */
    protected void callBeforeClass() throws Exception {
    }

    /**
     * Override to tear down test on AfterClass
     */
    protected void callAfterClass() throws Exception {
    }

    /**
     * Override to setup test on BeforeMethod
     */
    protected void callBeforeMethod() throws Exception {
    }

    /**
     * Override to tear down test on AfterMethod
     */
    protected void callAfterMethod() throws Exception {
    }

    /**
     * Override to setup Log4j
     */
    protected void setupLog4J() {
        BasicConfigurator.configure();
        org.apache.log4j.Logger.getRootLogger().setLevel(Level.INFO);
    }

    /**
     * Used to setup TransactionManager
     *
     * @param cfg current H3 configuration
     */
    protected void configureTransactionManager(Ejb3Configuration cfg) {
        cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, BTMTransactionManagerLookup.class.getName());
        cfg.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "jta");
        cfg.setProperty(AvailableSettings.TRANSACTION_TYPE, "JTA");
    }

    protected void configureDatabase(Ejb3Configuration cfg) {
        cfg.setProperty(Environment.HBM2DDL_AUTO, "create");
        cfg.setProperty(Environment.RELEASE_CONNECTIONS, "after_statement");
        cfg.setProperty(Environment.DATASOURCE, "test-" + getClass().getSimpleName());
        cfg.setProperty(Environment.DIALECT, H2Dialect.class.getName());
    }

    protected abstract void configureEntities(Ejb3Configuration cfg);

    protected void shutdownTransactionManager() {
        TransactionManagerServices.getTransactionManager().shutdown();
    }

    protected void shutdownEmf() {
        emf.close();
    }

    protected void beginTransaction() throws Exception {
        BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager();
        if (tm.getStatus() != Status.STATUS_NO_TRANSACTION) {
            throw new RuntimeException("Active transaction in progress! Please commit or roll it back!");
        }
        tm.begin();
    }

    protected void commitTransaction() throws Exception {
        BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager();
        if (tm.getStatus() != Status.STATUS_ACTIVE) {
            throw new RuntimeException("Transaction is not active and cannot be committed! Please start a new transaction first!");
        }
        tm.commit();
    }

    protected void rollbackTransaction() throws Exception {
        BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager();
        if (tm.getStatus() != Status.STATUS_ACTIVE && tm.getStatus() != Status.STATUS_MARKED_ROLLBACK) {
            throw new RuntimeException("Transaction is not active and cannot be rolled back! Please start a new transaction first!");
        }
        tm.rollback();
    }

    /**
     * Override to provide support for H2 compatibility mode
     *
     * @return DbMode to use with H2, null means don't use compatibility mode and act as a standard H2
     */
    protected DbMode compatibilityMode() {
        return null;
    }

    /**
     * Override to load test data into database used for test, the steps are as follow:
     * - beginTransaction()
     * - em.joinTransaction()
     * - ... test data ...
     * - commitTransaction() / rollbackTransaction()
     * - em.close()
     *
     * EM is working with real transactions so you must either commit or rollback active transaction.
     *
     * @param em active EM
     * @throws Exception
     */
    protected abstract void loadTestData(EntityManager em) throws Exception;

}
TOP

Related Classes of com.softwaremill.common.dbtest.TransactionalDBTest

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.