All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unitils.database.transaction.impl.DefaultUnitilsTransactionManager Maven / Gradle / Ivy

There is a newer version: 3.4.6
Show newest version
/*
 * 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.database.transaction.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.unitils.core.UnitilsException;
import org.unitils.database.transaction.UnitilsTransactionManager;

import javax.sql.DataSource;
import java.util.*;

/**
 * Implements transactions for unit tests, by delegating to a spring
 * PlatformTransactionManager. The concrete implementation of
 * PlatformTransactionManager that is used depends on the test
 * class. If a custom PlatformTransactionManager was configured
 * in a spring ApplicationContext, this one is used. If not, a
 * suitable subclass of PlatformTransactionManager is created,
 * depending on the configuration of a test. E.g. if some ORM persistence unit
 * was configured on the test, a PlatformTransactionManager that
 * can offer transactional behavior for such a persistence unit is used. If no
 * such configuration is found, a DataSourceTransactionManager is
 * used.
 *
 * @author Filip Neven
 * @author Tim Ducheyne
 */
public class DefaultUnitilsTransactionManager implements UnitilsTransactionManager {

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

    protected Map testObjectTransactionActiveMap = new HashMap();

    /**
     * ThreadLocal for holding the TransactionStatus that keeps track of the
     * current test's transaction status
     */
    protected Map testObjectTransactionStatusMap = new HashMap();

    /**
     * ThreadLocal for holding the PlatformTransactionManager that is used by
     * the current test
     */
    protected Map testObjectPlatformTransactionManagerMap = new HashMap();


    /**
     * Set of possible providers of a spring
     * PlatformTransactionManager, not null
     */
    protected List transactionManagementConfigurations;

    public void init(Set transactionManagementConfigurations) {
        setTransactionManagementConfigurations(transactionManagementConfigurations);
    }


    /**
     * Returns the given datasource, wrapped in a spring
     * TransactionAwareDataSourceProxy
     */
    public DataSource getTransactionalDataSource(DataSource dataSource) {
        return new TransactionAwareDataSourceProxy(dataSource);
    }


    /**
     * Starts the transaction. Starts a transaction on the
     * PlatformTransactionManager that is configured for the given testObject.
     *
     * @param testObject The test object, not null
     */
    public void startTransaction(Object testObject) {
        UnitilsTransactionManagementConfiguration transactionManagementConfiguration = getTransactionManagementConfiguration(testObject);
        if (transactionManagementConfiguration.isTransactionalResourceAvailable(testObject)) {
            testObjectTransactionActiveMap.put(testObject, Boolean.TRUE);
            doStartTransaction(testObject, transactionManagementConfiguration);
        } else {
            testObjectTransactionActiveMap.put(testObject, Boolean.FALSE);
        }
    }


    public void activateTransactionIfNeeded(Object testObject) {
        if (testObjectTransactionActiveMap.containsKey(testObject) && !testObjectTransactionActiveMap.get(testObject)) {
            testObjectTransactionActiveMap.put(testObject, Boolean.TRUE);
            UnitilsTransactionManagementConfiguration transactionManagementConfiguration = getTransactionManagementConfiguration(testObject);
            doStartTransaction(testObject, transactionManagementConfiguration);
        }
    }


    protected void doStartTransaction(Object testObject, UnitilsTransactionManagementConfiguration transactionManagementConfiguration) {
        logger.debug("Starting transaction");
        PlatformTransactionManager platformTransactionManager = transactionManagementConfiguration.getSpringPlatformTransactionManager(testObject);
        testObjectPlatformTransactionManagerMap.put(testObject, platformTransactionManager);
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(createTransactionDefinition(testObject));
        testObjectTransactionStatusMap.put(testObject, transactionStatus);
    }


    /**
     * Commits the transaction. Uses the PlatformTransactionManager and transaction
     * that is associated with the given test object.
     *
     * @param testObject The test object, not null
     */
    public void commit(Object testObject) {
        if (!testObjectTransactionActiveMap.containsKey(testObject)) {
            throw new UnitilsException("Trying to commit, while no transaction is currently active");
        }
        TransactionStatus transactionStatus = testObjectTransactionStatusMap.get(testObject);
        if (testObjectTransactionActiveMap.get(testObject)) {
            logger.debug("Committing transaction");
            testObjectPlatformTransactionManagerMap.get(testObject).commit(transactionStatus);
        }
        testObjectTransactionActiveMap.remove(testObject);
        testObjectTransactionStatusMap.remove(testObject);
        testObjectPlatformTransactionManagerMap.remove(testObject);
    }

    /**
     * Rolls back the transaction. Uses the PlatformTransactionManager and transaction
     * that is associated with the given test object.
     *
     * @param testObject The test object, not null
     */
    public void rollback(Object testObject) {
        if (!testObjectTransactionActiveMap.containsKey(testObject)) {
            throw new UnitilsException("Trying to rollback, while no transaction is currently active");
        }
        TransactionStatus transactionStatus = testObjectTransactionStatusMap.get(testObject);
        if (testObjectTransactionActiveMap.get(testObject)) {
            logger.debug("Rolling back transaction");
            testObjectPlatformTransactionManagerMap.get(testObject).rollback(transactionStatus);
        }
        testObjectTransactionActiveMap.remove(testObject);
        testObjectTransactionStatusMap.remove(testObject);
        testObjectPlatformTransactionManagerMap.remove(testObject);
    }

    /**
     * Returns a TransactionDefinition object containing the
     * necessary transaction parameters. Simply returns a default
     * DefaultTransactionDefinition object with the 'propagation
     * required' attribute
     *
     * @param testObject The test object, not null
     * @return The default TransactionDefinition
     */
    protected TransactionDefinition createTransactionDefinition(Object testObject) {
        return new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
    }


    protected UnitilsTransactionManagementConfiguration getTransactionManagementConfiguration(Object testObject) {
        for (UnitilsTransactionManagementConfiguration transactionManagementConfiguration : transactionManagementConfigurations) {
            if (transactionManagementConfiguration.isApplicableFor(testObject)) {
                return transactionManagementConfiguration;
            }
        }
        throw new UnitilsException("No applicable transaction management configuration found for test " + testObject.getClass());
    }


    protected void setTransactionManagementConfigurations(Set transactionManagementConfigurationsSet) {
        List configurations = new ArrayList();
        configurations.addAll(transactionManagementConfigurationsSet);
        Collections.sort(configurations, new Comparator() {

            public int compare(UnitilsTransactionManagementConfiguration o1, UnitilsTransactionManagementConfiguration o2) {
                return o2.getPreference().compareTo(o1.getPreference());
            }

        });
        this.transactionManagementConfigurations = configurations;
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy