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 {
}