On 06/21/2012 08:33 AM, Christian Romberg wrote:
> ... for my specific requirement, what should happen in txn.commit(), to
> make the JPA-JTA interaction work:
> (and probably this is already happening in all real-life
> implementations, but to my knowledge not a specified behavior)
>
> sync1.beforeCompletion(); //this will flush all pending changes
> through "con" which is still in the context of "xid1"
> res1.end(xid1, TMSUCCESS);
> res1.prepare(xid1);
> res1.commit(xid1);
>
> What should _not_ happen is:
> 1. That it is an illegal state, that res1.end(xid1) was not called, when
> txn.commit() is called
The JTA spec is basically a Java language mapping of the XA spec and,
although it's not explicit in the JTA spec, it's accepted practice that
the two documents should be read together. I'd argue the condition you
describe is covered by table 6-4 in the XA spec, which shows prepare and
commit are not valid in the active state i.e. you have to call end to
transition from active to idle before terminating the tx. The wording in
XA is also quite explicit on this point:
"Before a TM can call xa_prepare () for a transaction branch, all
associations must be completely ended with xa_end()"
and of the xa_prepare call:
"All associations for ∗xid must have been ended by using xa_end() with
TMSUCCESS set in flags"
So an XAResource.prepare is within its rights to (and arguably must)
generate XAER_PROTO if called before an end call.
The situation with rollbacks is a little more ambiguous as the
xa_rollback spec does not contain similar wording.
> 2. That "beforeCompletion()" is fired _after_ res1.end(xid1) was called
Hmm, I think rather it's the case that, at the time beforeCompletion is
executed, the XAResource must be associated. It's valid for end(suspend)
to be called prior to that, provided start(resume) has also been called.
What you're really trying to achieve is that the Connection behaves as
enlisted in the tx. IMO that's covered by a combination of provisions in
the JTA and JCA specs, albeit somewhat tenuously.
"This [beforeCompletion] call is executed with the transaction context
of the transaction that is being committed." - JTA 1.1 page 33. That
is, the spec assures that calling getConnection() from a
beforeCompletion gives you an appropriately enlisted Connection.
As for cached connection, most JCAs will also guarantee that a
previously obtained and cached connection will function correctly in
such cases, but that's really a JCA matter. It hinges on: is the
Synchronization considered an application component (per JCA 1.5 s2.1.8)
for the purposes of JCA s7.14.2:
"Irrespective of how a transaction is started, an application server
enlists all connections (cached or newly acquired by an application
component) with the transaction, so that the work done using those
connections will be part of the transaction. This enlistment happens
before the method call in the case of cached connections and during the
method call when connections are newly acquired within the transaction"
This could arguably use some clarification, though IMO it belong in the
JCA rather than JTA spec.
As a practical matter I think you'll find most transaction manager
implementers are pretty pragmatic and accustomed to tackling ambiguities
in the spec in a way that produces fewest surprises for users of their
software. Certainly as a former JBossTS dev lead I'd consider the
behaviour you describe to be the expectation of users and the intent of
the spec, despite the lack of explicit wording for it.
If you have trouble with a transaction manager not behaving in the
expected way I'd approach its authors first, as you've probably found a
bug they are happy to fix. Refining the spec is a worthwhile but endless
process. Fortunately we can mostly get along with an imperfect one.
Jonathan.
--
Registered in England and Wales under Company Registration No. 03798903
Directors: Michael Cunningham (USA), Mark Hegarty (Ireland), Matt Parson
(USA), Charlie Peters (USA)