package org.test4j.module.database.transaction; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.sql.DataSource; 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.test4j.module.Test4JException; import org.test4j.module.core.TestContext; import org.test4j.module.core.utility.MessageHelper; /** * 默认事务管理类 * * @author darui.wudr */ public class DefaultTransactionManager implements TransactionManager { protected Map<Object, Boolean> testObjectTransactionActiveMap = new HashMap<Object, Boolean>(); /** * ThreadLocal for holding the TransactionStatus that keeps track of the * current test's transaction status */ protected Map<Object, TransactionStatus> testObjectTransactionStatusMap = new HashMap<Object, TransactionStatus>(); /** * ThreadLocal for holding the PlatformTransactionManager that is used by * the current test */ protected Map<Object, PlatformTransactionManager> testObjectPlatformTransactionManagerMap = new HashMap<Object, PlatformTransactionManager>(); /** * Set of possible providers of a spring * <code>PlatformTransactionManager</code>, not null */ protected List<TransactionManagementConfiguration> transactionManagementConfigurations; public void init(Set<TransactionManagementConfiguration> transactionManagementConfigurations) { setTransactionManagementConfigurations(transactionManagementConfigurations); } /** * Returns the given datasource, wrapped in a spring * <code>TransactionAwareDataSourceProxy</code> */ public DataSource getTransactionalDataSource(DataSource dataSource) { return new TransactionAwareDataSourceProxy(dataSource); } public void startTransaction() { Object testObject = TestContext.currTestedObject(); TransactionManagementConfiguration 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 = TestContext.currTestedObject(); Boolean hasActived = testObjectTransactionActiveMap.get(testObject); if (hasActived == Boolean.FALSE) { testObjectTransactionActiveMap.put(testObject, Boolean.TRUE); TransactionManagementConfiguration transactionManagementConfiguration = getTransactionManagementConfiguration(testObject); doStartTransaction(testObject, transactionManagementConfiguration); } } protected void doStartTransaction(Object testObject, TransactionManagementConfiguration transactionManagementConfiguration) { MessageHelper.debug("Starting transaction"); PlatformTransactionManager platformTransactionManager = transactionManagementConfiguration .getSpringPlatformTransactionManager(testObject); testObjectPlatformTransactionManagerMap.put(testObject, platformTransactionManager); TransactionDefinition definition = createTransactionDefinition(testObject); TransactionStatus transactionStatus = platformTransactionManager.getTransaction(definition); testObjectTransactionStatusMap.put(testObject, transactionStatus); } public void commit() { Object testObject = TestContext.currTestedObject(); Boolean hasActived = testObjectTransactionActiveMap.containsKey(testObject); if (hasActived == null) { throw new Test4JException("Trying to commit, while no transaction is currently active"); } TransactionStatus transactionStatus = testObjectTransactionStatusMap.get(testObject); if (hasActived == Boolean.TRUE && transactionStatus != null) { MessageHelper.debug("Committing transaction"); testObjectPlatformTransactionManagerMap.get(testObject).commit(transactionStatus); } removeTestedObjectTransactionManager(testObject); } public void rollback() { Object testObject = TestContext.currTestedObject(); Boolean hasActived = testObjectTransactionActiveMap.containsKey(testObject); if (hasActived == null) { throw new Test4JException("Trying to rollback, while no transaction is currently active"); } TransactionStatus transactionStatus = testObjectTransactionStatusMap.get(testObject); if (hasActived == Boolean.TRUE && transactionStatus != null) { MessageHelper.debug("Rolling back transaction"); testObjectPlatformTransactionManagerMap.get(testObject).rollback(transactionStatus); } removeTestedObjectTransactionManager(testObject); } /** * 移除测试对象的事务管理对象 * * @param testObject */ private void removeTestedObjectTransactionManager(Object testObject) { testObjectTransactionActiveMap.remove(testObject); testObjectTransactionStatusMap.remove(testObject); testObjectPlatformTransactionManagerMap.remove(testObject); } /** * Returns a <code>TransactionDefinition</code> object containing the * necessary transaction parameters. Simply returns a default * <code>DefaultTransactionDefinition</code> 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 TransactionManagementConfiguration getTransactionManagementConfiguration(Object testObject) { for (TransactionManagementConfiguration transactionManagementConfiguration : transactionManagementConfigurations) { if (transactionManagementConfiguration.isApplicableFor(testObject)) { return transactionManagementConfiguration; } } throw new Test4JException("No applicable transaction management configuration found for test " + testObject.getClass()); } protected void setTransactionManagementConfigurations(Set<TransactionManagementConfiguration> transactionManagementConfigurationsSet) { List<TransactionManagementConfiguration> configurations = new ArrayList<TransactionManagementConfiguration>(); configurations.addAll(transactionManagementConfigurationsSet); Collections.sort(configurations, new Comparator<TransactionManagementConfiguration>() { public int compare(TransactionManagementConfiguration o1, TransactionManagementConfiguration o2) { return o2.getPreference().compareTo(o1.getPreference()); } }); this.transactionManagementConfigurations = configurations; } }