... with every spec I read. I'm through JMX, JTA,
and JDBC standard extension so far...
I haven't tried to fit into the JDBC connection pooling mechanism,
since I had planned to use this outside of the context of an application
server as well (and thus, it should be useful without a PooledDataSource
or whatever). I may have to rethink that - I'm not sure I can make a
clean split between the transactional capabilities and the "dumb"
implementation.
In any case, it seems like I have further transactional problems.
According to the JDBC spec, I think this is what is supposed to happen:
1) Bean requests connection
2) Pool generates connection
3) XAResource is associated with connection
4) XAResource is registered with TransactionManager (seems to be via
Transaction.enlistResource)
5) TransactionManager calls start(...) on XAResource (not my problem)
6) Connection is returned to bean
7) Connection behavior is different depending on whether it currently is
or is not part of a global transaction. According to the JDBC spec (7.5):
"A TX_BEAN_MANAGED bean may even use the same JDBC Connection both inside
and outside of a global transaction." - which seems to mean that for every
relevant method invocation (commit, rollback, setAutoCommit), the
connection must determine from the XAResource whether it is or is not
currently part of a global transaction (how?).
8) Bean calls close on connection. Connection is left in limbo (not in
use, not in pool)
9) TransactionManager calls commit/rollback methods on XAResource
(not my problem)
10) XAResource calls appropriate commit/rollback methods on connection and
returns connection to the pool.
I'm really unsure about point #8. If the bean calls close() on
the connection, the JTA spec (3.4.2) seems to indicate that the connection
should be dissociated from the transaction, without ending the transaction
(does that imply a commit or rollback?), and then returned to the pool of
available connections. So then the only way for a bean's work to get
committed is for the bean to never call close(), so that the
TransactionManager does the commit - but then how do you know when to
release the connection back to the pool? Can you assume that when the
XAResource's end method is called (indicating the end of a transaction),
the connection is returned to the pool? This seems contrary to the part
of the JTA spec (3.4.4) that talks about how a resource can be associated
with several transactions over time.
All this led me to interpretation 8, which seems contrary to the
spec, but works. Sigh.
On to other problems. If I understand this right, the
connection/XAResource never initiates a transaction. Either the container
initiates a transaction before the bean ever requests the connection, or
the bean is responsible for all transactional boundaries (and must
manually commit or rollback on the connection).
So other than confirming the sequence above, I have one major
question left. The only place we can run into trouble (that is, a
connection isn't committed or rolled back or released to the pool for a
long period of time - say, 20+ minutes) is when the clients or beans
manage their own transactions (is this distinct from bean-managed
persistance?). In that case, it's not clear whether an XAResource would
be necessary. Can a bean create a UserTransaction and get a connection
and then register the connection's XAResource with the UserTransaction? If
so, then there needs to be a public way to get an XAResource, and if not
the XAResource can be managed entirely within the container.
In any case, I suppose the connection and XAResource should both
be wrappers around the physical databsae connection. So if too much time
passes, the physical connection can be returned to the pool, and the
wrappers can have their implementations nulled out. Then if you call
anything on the connection, you get a SQLException, and the XAResource
refuses to do anything but rollback.
Aaron