users@jta-spec.java.net

[jta-spec users] rough draft of JTA 1.2 section 3.8 TransactionScoped Annotation

From: Paul Parkinson <paul.parkinson_at_oracle.com>
Date: Tue, 27 Nov 2012 10:48:46 -0500

Hi,

Below is a rough first run of JTA 1.2 section 3.8 TransactionScoped Annotation, http://java.net/jira/browse/JTA_SPEC-7 .

These two issues remain open:

1. Do we want to keep the scope open until after Synchronization.afterCompletion completes? There is no transaction available in afterCompletion, but developers may need to do tidy-up on the TransactionScoped beans that will no longer be available. If users include a @PreDestroy method to do cleanup after the transaction has completed the spec needs to be clear that the transaction has completed when the @PreDestroy method is called.

2. Is the transaction scope itself volatile and not recoverable? It would seem so. Do we make the chosen behaviour explicit in the spec?

Thank you for any feedback on these open issues as well as any feedback on the spec draft in general (eg suggestions as far as the example presented) as we need to close this down in the next couple weeks.

Thanks,
Paul




3.8 TransactionScoped Annotation

The javax.transaction.TransactionScoped annotation provides the ability to specify a standard scope to define beans whose lifecycle are scoped to the currently active JTA transaction.
 
The transaction scope is active when the return from a call to UserTransaction.getStatus or TransactionManager.getStatus is one of the following states:
        Status.STATUS_ACTIVE
        Status.STATUS_MARKED_ROLLBACK
        Status.STATUS_PREPARED
        Status.STATUS_UNKNOWN
        Status.STATUS_PREPARING
        Status.STATUS_COMMITTING
        Status.STATUS_ROLLING_BACK

The transaction context is destroyed after any Synchronization.beforeCompletion methods are called and afterCompletion calls have been made on enlisted resources. Synchronization.afterCompletion calls may occur before the transaction context is destroyed, however, there is no guarantee.

A javax.enterprise.context.ContextNotActiveException will be thrown if an object with this annotation is used when the transaction context is not active. The object with this annotation is associated with the JTA transaction where it is first used and this association is retained through any transaction suspend or resume calls as well as any beforeCompletion Synchronization calls until the transaction is completed. The way in which the JTA transaction is begun and completed (eg BMT, CMT, etc.) is of no consequence. The contextual references used across different JTA transactions are distinct. The following example test cases illustrate the expected behavior:

TransactionScoped annotated CDI managed bean:


@TransactionScoped

public class TestCDITransactionScopeBean {

        public void test() { //...

        }

}



Test Class:


UserTransaction userTransaction;

TransactionManager transactionManager;

@Inject

TestCIDTransactionScopeBean TestCIDTransactionScopeBean;


public void testTxAssociationChange() throws Exception {

        userTransaction.begin(); //tx1 begun

        testTxAssociationChangeBean.test(); //testTxAssociationChangeBean instance has tx1 association

        Transaction transaction = transactionManager.suspend(); //tx1 suspended

        //assert testTxAssociationChangeBean still associated with tx1 and that no transaction scope is active.

        userTransaction.begin(); //tx2 begun

        testTxAssociationChangeBean.test(); //assert new testTxAssociationChangeBean instance has tx2 association

        userTransaction.commit(); //tx2 committed, assert no transaction scope is active

        transactionManager.resume(tx); //tx1 resumed

        testTxAssociationChangeBean.test();

        //assert testTxAssociationChangeBean is original tx1 instance and not still referencing committed/tx2 tx

        userTransaction.commit(); //tx1 commit, assert no transaction scope is active

        try {

                testTxAssociationChangeBean.test(); fail(“should have thrown ContextNotActiveException”);

        } catch (ContextNotActiveException ContextNotActiveException) {

                // do nothing intentionally

        }

    }



“Java Transaction API Reference” on page 30 has a full description of this annotation

[...]


/**
 * Annotation used to indicate a bean is to be scoped to the currently active
 * JTA transaction.
 *
 * The transaction scope is active when the return from a call to
 * <code>UserTransaction.getStatus</code> or
 * <code>TransactionManager.getStatus</code>
 * is one of the following states:
 * <li>Status.STATUS_ACTIVE</li>
 * <li>Status.STATUS_MARKED_ROLLBACK</li>
 * <li>Status.STATUS_PREPARED</li>
 * <li>Status.STATUS_UNKNOWN</li>
 * <li>Status.STATUS_PREPARING</li>
 * <li>Status.STATUS_COMMITTING</li>
 * <li>Status.STATUS_ROLLING_BACK</li>
 *
 * The transaction context is destroyed after any
 * <code>Synchronization.beforeCompletion</code> methods are called and
 * afterCompletion calls have been made on enlisted resources.
 * <code>Synchronization.afterCompletion</code> calls may occur before
 * the transaction context is destroyed, however, there is no guarantee.
 *
 * A <code>javax.enterprise.context.ContextNotActiveException</code>
 * will be thrown if an object with this annotation is used when the
 * transaction context is not active.
 * The object with this annotation is associated with the JTA transaction where
 * it is first used and this association is retained through any transaction
 * suspend or resume calls as well as any beforeCompletion Synchronization
 * calls until the transaction is completed.
 * The way in which the JTA transaction is begun and completed
 * (eg BMT, CMT, etc.) is of no consequence.
 * The contextual references used across different JTA transactions are
 * distinct.
 *
 * @since JTA1.2
 */
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@NormalScope(passivating=true)
public @interface TransactionScoped {
}