/**
   * If the test method of the supplied {@link TestContext test context} is configured to run within
   * a transaction, this method will run {@link BeforeTransaction @BeforeTransaction methods}
   * and start a new transaction.
   *
   * <p>Note that if a {@code @BeforeTransaction} method fails, any remaining
   * {@code @BeforeTransaction} methods will not be invoked, and a transaction will not be started.
   *
   * @see org.springframework.transaction.annotation.Transactional
   * @see #getTransactionManager(TestContext, String)
   */
  @SuppressWarnings("serial")
  @Override
  public void beforeTestMethod(TestContext testContext) throws Exception {
    final Method testMethod = testContext.getTestMethod();
    Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");

    if (this.transactionContextCache.remove(testMethod) != null) {
      throw new IllegalStateException(
          "Cannot start new transaction without ending existing transaction: "
              + "Invoke endTransaction() before startNewTransaction().");
    }

    PlatformTransactionManager tm = null;
    TransactionAttribute transactionAttribute =
        this.attributeSource.getTransactionAttribute(testMethod, testContext.getTestClass());

    if (transactionAttribute != null) {
      transactionAttribute =
          new DelegatingTransactionAttribute(transactionAttribute) {

            @Override
            public String getName() {
              return testMethod.getName();
            }
          };

      if (logger.isDebugEnabled()) {
        logger.debug(
            "Explicit transaction definition ["
                + transactionAttribute
                + "] found for test context "
                + testContext);
      }

      if (transactionAttribute.getPropagationBehavior()
          == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
        return;
      }

      tm = getTransactionManager(testContext, transactionAttribute.getQualifier());
    }

    if (tm != null) {
      TransactionContext txContext = new TransactionContext(tm, transactionAttribute);
      runBeforeTransactionMethods(testContext);
      startNewTransaction(testContext, txContext);
      this.transactionContextCache.put(testMethod, txContext);
    }
  }
  @Override
  public void rollback(
      PlatformTransactionManager platformTransactionManager,
      Throwable throwable,
      TransactionAttribute transactionAttribute,
      TransactionStatus transactionStatus)
      throws Throwable {

    if (transactionAttribute.rollbackOn(throwable)) {
      try {
        platformTransactionManager.rollback(transactionStatus);
      } catch (RuntimeException re) {
        re.addSuppressed(throwable);

        _log.error("Application exception overridden by rollback exception", re);

        throw re;
      } catch (Error e) {
        e.addSuppressed(throwable);

        _log.error("Application exception overridden by rollback error", e);

        throw e;
      }
    } else {
      commit(platformTransactionManager, transactionAttribute, transactionStatus);
    }

    throw throwable;
  }
Esempio n. 3
0
 /**
  * checks method (and as a fallback the class) for the Spring {@link Transactional} annotation.
  *
  * @param mi Non-null method invocation.
  * @return true if the {@link Transactional} annotation lists this method as read-only, or if no
  *     annotation is found.
  */
 boolean checkReadOnly(MethodInvocation mi) {
   TransactionAttribute ta =
       txSource.getTransactionAttribute(mi.getMethod(), mi.getThis().getClass());
   return ta == null ? true : ta.isReadOnly();
 }