org.unitils.orm.hibernate.HibernateModule.java Source code

Java tutorial

Introduction

Here is the source code for org.unitils.orm.hibernate.HibernateModule.java

Source

/*
 * Copyright 2008,  Unitils.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.unitils.orm.hibernate;

import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.unitils.util.PropertyUtils.getString;

import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Set;

import javax.sql.DataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.unitils.core.Module;
import org.unitils.core.TestListener;
import org.unitils.core.UnitilsException;
import org.unitils.database.DataSourceWrapper;
import org.unitils.database.transaction.impl.UnitilsTransactionManagementConfiguration;
import org.unitils.database.util.Flushable;
import org.unitils.orm.common.OrmModule;
import org.unitils.orm.common.util.ConfiguredOrmPersistenceUnit;
import org.unitils.orm.common.util.OrmConfig;
import org.unitils.orm.common.util.OrmPersistenceUnitLoader;
import org.unitils.orm.hibernate.annotation.HibernateSessionFactory;
import org.unitils.orm.hibernate.util.HibernateAnnotationConfigLoader;
import org.unitils.orm.hibernate.util.HibernateAssert;
import org.unitils.orm.hibernate.util.HibernateSessionFactoryLoader;
import org.unitils.orm.jpa.annotation.JpaEntityManagerFactory;
import org.unitils.util.AnnotationUtils;
import org.unitils.util.ReflectionUtils;

/**
 * Module providing support for unit tests for code that uses Hibernate. It offers an easy way of loading hibernate 
 * SessionFactories and having them injected them into the test. It also offers a test to check whether the hibernate 
 * mapping is consistent with the structure of the database. 
 * <p/>
 * A Hibernate <code>SessionFactory</code> is created when requested and injected into all fields or methods of the test 
 * annotated with {@link HibernateSessionFactory}. 
 * <p/>
 * It is highly recommended to write a unit test that invokes {@link HibernateUnitils#assertMappingWithDatabaseConsistent()},
 * This is a very useful test that verifies whether the mapping of all your Hibernate mapped objects still corresponds
 * with the actual structure of the database.
 *
 * @author Filip Neven
 * @author Tim Ducheyne
 */
public class HibernateModule extends
        OrmModule<SessionFactory, Session, Configuration, HibernateSessionFactory, OrmConfig, HibernateAnnotationConfigLoader>
        implements Module, Flushable {

    /* Property that defines the class name of the hibernate configuration */
    public static final String PROPKEY_CONFIGURATION_CLASS_NAME = "HibernateModule.configuration.implClassName";

    /* The logger instance for this class */
    private static Log logger = LogFactory.getLog(HibernateModule.class);

    /**
     * Subclass of org.hibernate.cfg.Configuration that is used for configuring hibernate
     */
    private Class<? extends Configuration> configurationObjectClass;

    /**
     * @param configuration The Unitils configuration, not null
     */
    public void init(Properties configuration) {
        super.init(configuration);

        String configurationImplClassName = getString(PROPKEY_CONFIGURATION_CLASS_NAME, configuration);
        configurationObjectClass = ReflectionUtils.getClassWithName(configurationImplClassName);
    }

    public void afterInit() {
        super.afterInit();

    }

    public void registerTransactionManagementConfiguration() {
        // Make sure that a spring HibernateTransactionManager is used for transaction management in the database module, if the
        // current test object defines a hibernate SessionFactory
        for (final DataSourceWrapper wrapper : wrappers) {
            getDatabaseModule()
                    .registerTransactionManagementConfiguration(new UnitilsTransactionManagementConfiguration() {

                        public boolean isApplicableFor(Object testObject) {
                            return isPersistenceUnitConfiguredFor(testObject);
                        }

                        public PlatformTransactionManager getSpringPlatformTransactionManager(Object testObject) {
                            SessionFactory sessionFactory = getPersistenceUnit(testObject);
                            HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager(
                                    sessionFactory);
                            hibernateTransactionManager.setDataSource(getDataSource());
                            return hibernateTransactionManager;
                        }

                        public boolean isTransactionalResourceAvailable(Object testObject) {
                            return wrapper.isDataSourceLoaded();
                        }

                        public Integer getPreference() {
                            return 10;
                        }

                    });
        }

    }

    @Override
    protected HibernateAnnotationConfigLoader createOrmConfigLoader() {
        return new HibernateAnnotationConfigLoader();
    }

    @Override
    protected Class<HibernateSessionFactory> getPersistenceUnitConfigAnnotationClass() {
        return HibernateSessionFactory.class;
    }

    @Override
    protected Class<SessionFactory> getPersistenceUnitClass() {
        return SessionFactory.class;
    }

    @Override
    protected OrmPersistenceUnitLoader<SessionFactory, Configuration, OrmConfig> createOrmPersistenceUnitLoader() {
        return new HibernateSessionFactoryLoader(databaseName);
    }

    @Override
    protected String getOrmSpringSupportImplClassName() {
        return "org.unitils.orm.hibernate.util.HibernateSpringSupport";
    }

    @Override
    protected Session doGetPersistenceContext(Object testObject) {
        return SessionFactoryUtils.getSession(getPersistenceUnit(testObject), true);
    }

    @Override
    protected Session doGetActivePersistenceContext(Object testObject) {
        SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager
                .getResource(getPersistenceUnit(testObject));
        if (sessionHolder != null && sessionHolder.getSession() != null && sessionHolder.getSession().isOpen()) {
            return sessionHolder.getSession();
        }
        return null;
    }

    @Override
    protected void flushOrmPersistenceContext(Session activeSession) {
        logger.info("Flushing session " + activeSession);
        activeSession.flush();
    }

    /**
     * Checks if the mapping of the Hibernate managed objects with the database is correct.
     *
     * @param testObject The test instance, not null
     */
    public void assertMappingWithDatabaseConsistent(Object testObject) {
        ConfiguredOrmPersistenceUnit<SessionFactory, Configuration> configuredPersistenceUnit = getConfiguredPersistenceUnit(
                testObject);
        Configuration configuration = configuredPersistenceUnit.getOrmConfigurationObject();
        Session session = getPersistenceContext(testObject);
        Dialect databaseDialect = getDatabaseDialect(configuration);

        HibernateAssert.assertMappingWithDatabaseConsistent(configuration, session, databaseDialect);
    }

    /**
     * @return The subclass of <code>org.hibernate.cfg.Configuration</code> that is used for configuring hibernate
     */
    public Class<? extends Configuration> getConfigurationObjectClass() {
        return configurationObjectClass;
    }

    /**
     * Gets the database dialect from the given Hibernate <code>Configuration</code.
     *
     * @param configuration The hibernate config, not null
     * @return the database Dialect, not null
     */
    protected Dialect getDatabaseDialect(Configuration configuration) {
        String dialectClassName = configuration.getProperty("hibernate.dialect");
        if (isEmpty(dialectClassName)) {
            throw new UnitilsException("Property hibernate.dialect not specified");
        }
        try {
            return (Dialect) Class.forName(dialectClassName).newInstance();
        } catch (Exception e) {
            throw new UnitilsException("Could not instantiate dialect class " + dialectClassName, e);
        }
    }

    protected DataSource getDataSource() {
        return getDatabaseModule().getWrapper(databaseName).getDataSourceAndActivateTransactionIfNeeded();
    }

    /**
     * @return The TestListener associated with this module
     */
    public TestListener getTestListener() {
        return new HibernateTestListener();
    }

    /**
     * The {@link TestListener} for this module
     */
    protected class HibernateTestListener extends OrmTestListener {

        /**
         * @see org.unitils.core.TestListener#beforeTestMethod(java.lang.Object, java.lang.reflect.Method)
         */
        @Override
        public void beforeTestMethod(Object testObject, Method testMethod) {
            //databaseName = getDatabaseName(testObject, testMethod);
            registerTransactionManagementConfiguration();
            super.beforeTestMethod(testObject, testMethod);
        }

    }

    /**
     * @see org.unitils.orm.common.OrmModule#getDatabaseName(java.lang.Object, java.lang.reflect.Method)
     */
    @Override
    protected void getDatabaseName(Object testObject, Method testMethod) {
        //List<String> dataSources = new ArrayList<String>();
        HibernateSessionFactory dataSource = AnnotationUtils
                .getMethodOrClassLevelAnnotation(HibernateSessionFactory.class, testMethod, testObject.getClass());
        if (dataSource != null) {
            wrappers.add(getDatabaseModule().getWrapper(dataSource.databaseName()));
            //dataSources.add(dataSource.databaseName());

        }

        Set<HibernateSessionFactory> lstDataSources = AnnotationUtils
                .getFieldLevelAnnotations(testObject.getClass(), HibernateSessionFactory.class);
        if (!lstDataSources.isEmpty()) {
            for (HibernateSessionFactory testDataSource : lstDataSources) {
                //ataSources.add(testDataSource.databaseName());
                wrappers.add(getDatabaseModule().getWrapper(testDataSource.databaseName()));
            }
        }
        //return dataSources;

    }

}