users@jta-spec.java.net

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

From: Jonathan Halliday <jonathan.halliday_at_redhat.com>
Date: Tue, 27 Nov 2012 17:14:11 +0000

1) I'm undecided if I love or hate that 'active' finally has an explicit
definition in terms of its Status set. I know I loathe that the set of
States that define it includes UNKNOWN though.

As for the rest, I love it because it removes ambiguity, but I hate it
because the existing spec does not so define 'active' or 'inactive' in
relation to transaction contexts and the expected behaviour of existing
methods in the API.

The existing spec leaves scope for differing interpretation, from 'an
active transaction is one with Status.STATUS_ACTIVE only' through 'an
active transaction is one that has not yet terminated, i.e. also
includes Status.STATUS_MARKED_ROLLBACK and possibly other non-terminal
states.

Considered in isolation, the strict definition of 'active' in relation
to transaction scope is a Good Thing. My concern is that when read as
part of the overall spec, it may be interpreted as being intended to
apply the same definition to 'active' in terms of transaction context
also, i.e. be thought to retroactively define how the term should be
interpreted elsewhere in the spec.

I'd be strongly inclined to remove this possible implication by
retrofitting the spec preamble with a brief comment on the intended
definition of the terms 'active' and 'inactive' in relation to
transaction contexts (i.e. use other than in relation to the new
transaction scopes). If that definition should be strict or loose is
outside the scope of this discussion. Perhaps it should just make clear
that it's not intended that the terms as defined in relation to
transaction scope should also apply to its use in relation to
transaction context/lifecycle.


2) There is a known issue with the behaviour of containers and
applications as regards the asynchronous processing of transaction
termination. Essentially a Thread's tx Status or context can change
without warning, if another Thread acts concurrently on that context.
This occurs primarily if a tx timeout is processed in the background,
although as app concurrency increases I suspect we'll see it happen more
due to the actions of concurrent application Threads also. It causes
problems with e.g. a JDBC Connection handle that previously was under
transaction control suddenly reverting to local-tx auto-commit mode.
Fixing this is itself a matter for spec revision, but let's limit the
discussion to transaction scopes for now.

By the same reasoning, the tx scope a Thread is running in may change
other than through that Thread's actions. At minimum the user should be
made aware of this problem so that they can make some effort to code
defensively. At best it should be ensured that harmful side effects are
not permitted. The JDBC Connection handle thing for example would be
fine if the Connection handle was closed or otherwise invalidated
instead of reverting to auto-commit, since the app would then detect the
tx status change indirectly via an attempted action on the Connection
throwing an exception. It may be that a 'null scope' or some similar
pseudo environment exists for use where the tx scope is undefined.

Passing a managed handle/reference of any sort obtained in one tx scope
across a tx scope boundary to another tx scope (even unwittingly on the
same Thread, such as in the async Status change case) should make clear
the expected semantics of that handle in its new environment, or you'll
wind up having the same problem with scopes that currently exists with
contexts.

The javadoc mention of 'associated where first used' and 'across
suspend/resume' could be extended to treat tx context change as
equivalent to a suspend/resume even where such methods are not
explicitly called, which may be what's intended?


3) Is it felt necessary to address the behaviour of scopes in
distributed (i.e. multi-JVM) transactions? This is not the case for TSR
get/put behaviour for example, with most implementations opting to
consider the TSR storage to be node local, hence not allowing a put in
one container to be visible to a get in anther container, even if the
logical transaction context is equivalent. I think it's reasonable for
scopes to behave likewise, but do we want to enforce that they should
(or should not)?

Speaking of TSR, it seems the tx-context-local Map underpinning the
TSR.get/put methods may be a likely candidate for use in implementation
of scopes, forming a handy place to cache resolved references or such.
Is it necessary/desirable to tweak the TSR definition to ensure this
implementation route is possible? I guess that loops back to the
earlier discussion on 'active' in relation to tx contexts rather than tx
scopes - it would be necessary to ensure consistency between the
behaviour of TSR.get/put and the definition used by scopes.


Jonathan.

On 11/27/2012 03:48 PM, Paul Parkinson wrote:
> 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 {
> }

-- 
Registered in England and Wales under Company Registration No. 03798903 
Directors: Michael Cunningham (USA), Mark Hegarty (Ireland), Matt Parson
(USA), Charlie Peters (USA)