Transactional ConnectionEventListener tracking
The Java EE Connector Architecture has a concept called a ConnectionEventListener which is the mechanism that a resource adapter notifies the ConnectionManager that a connection handle isn't longer in use, or had an error occur on it. The ConnectionManager uses these notifications to know when a ManagedConnection can be returned to the pool, since the ConnectionEventListener keeps track of the connection handles registered and unregistred. Another dimension comes into play when the ManagedConnection is enlisted in a transaction, e.g. when the resource adapter is deployed with either LocalTransaction or XATransaction as its transaction setting. The XAResource instance associated, either through the IronJacamar container in the case of LocalTransaction or the instance directly attached to the ManagedConnection in the case of XATransaction is enlisted on the active transaction through the tx.enlistResource(xaResource) method call, and the ManagedConnection is "scoped" to the transaction itself. However, that present a problem when a connection handle is used across transactional boundaries, like
// UserTransaction instance bound to 'ut', and DataSource instance bound to 'ds'
Connection c = null;
// Transaction #1
ut.begin();
c = ds.getConnection();
ut.commit();
// Transaction #2
ut.begin();
c.close();
ut.commit();
because at the end of
Transaction #1
the associated
XAResource
is delisted from the transaction, but the
ManagedConnection
can't be returned to the pool, as there is still a connection handle associated. This means that usage of the
connection handle in
Transaction #2
can't be determined in a transactional context, since there is no
XAResource
associated with
Transaction #2
. The
c.close()
will allow the
ManagedConnection
instance to be returned to the pool, but not on transactional boundary itself.
This scenario is due to application usage errors, so we should detect and highlight the problem to the developers.
There is a new deployment attribute called
tracking
which can be used to enable tracking of the transactional
ConnectionEventListener
over the transactional boundaries.
The IronJacamar default setting will be to only report that it has detected the problem, and have therefore destroyed
the associated
ManagedConnection
instance, as it can't be trusted anymore.
Connection c = null;
// Transaction #1
ut.begin();
c = ds.getConnection();
ut.commit();
// Transaction #2
ut.begin();
c.close();
ut.commit();
11:31:32,952 ERROR [TxConnectionListener] IJ000315: Pool TxLog has 1 active handles
By setting
tracking
to
true
you will get a full trace of where the connection handle was allocated, and where the transaction boundary ended
11:31:32,952 ERROR [TxConnectionListener] IJ000315: Pool TxLog has 1 active handles
11:31:32,953 ERROR [TxConnectionListener] IJ000316: Handle allocation: TxLogConnection@520c87f3[mc=TxLogManagedConnection@7f0eb91e[txState=3B8]]: java.lang.Exception at org.jboss.jca.core.connectionmanager.listener.AbstractConnectionListener.registerConnection(AbstractConnectionListener.java:281) at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.registerAssociation(AbstractConnectionManager.java:880) at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:590) at org.jboss.jca.core.tx.rars.txlog.TxLogConnectionFactoryImpl.getConnection(TxLogConnectionFactoryImpl.java:80) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testBase(AcrossTransactionTestCase.java:197) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testXA(AcrossTransactionTestCase.java:254)
11:31:32,955 ERROR [TxConnectionListener] IJ000317: Transaction boundary: java.lang.Exception at org.jboss.jca.core.connectionmanager.listener.TxConnectionListener$TransactionSynchronization.afterCompletion(TxConnectionListener.java:1028) at org.jboss.jca.core.connectionmanager.transaction.TransactionSynchronizer.invokeAfter(TransactionSynchronizer.java:397) at org.jboss.jca.core.connectionmanager.transaction.TransactionSynchronizer.afterCompletion(TransactionSynchronizer.java:343) at org.jboss.jca.core.tx.vts.TransactionImpl.finish(TransactionImpl.java:402) at org.jboss.jca.core.tx.vts.TransactionImpl.commit(TransactionImpl.java:99) at org.jboss.jca.core.tx.vts.TxRegistry.commitTransaction(TxRegistry.java:79) at org.jboss.jca.core.tx.vts.UserTransactionImpl.commit(UserTransactionImpl.java:115) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testBase(AcrossTransactionTestCase.java:199) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testXA(AcrossTransactionTestCase.java:254)
For
XATransaction
with interleaving scenarios the error code
IJ000318
will be reported.
By setting
tracking
to
false
you will get the old behavior, where the
ManagedConnection
will be valid across the transactional boundaries, but only enlisted during the first transaction.
The IronJacamar community hopes that this new feature will help developers to find application code, which has been assuming certain conditions that weren't valid.
11:31:32,953 ERROR [TxConnectionListener] IJ000316: Handle allocation: TxLogConnection@520c87f3[mc=TxLogManagedConnection@7f0eb91e[txState=3B8]]: java.lang.Exception at org.jboss.jca.core.connectionmanager.listener.AbstractConnectionListener.registerConnection(AbstractConnectionListener.java:281) at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.registerAssociation(AbstractConnectionManager.java:880) at org.jboss.jca.core.connectionmanager.AbstractConnectionManager.allocateConnection(AbstractConnectionManager.java:590) at org.jboss.jca.core.tx.rars.txlog.TxLogConnectionFactoryImpl.getConnection(TxLogConnectionFactoryImpl.java:80) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testBase(AcrossTransactionTestCase.java:197) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testXA(AcrossTransactionTestCase.java:254)
11:31:32,955 ERROR [TxConnectionListener] IJ000317: Transaction boundary: java.lang.Exception at org.jboss.jca.core.connectionmanager.listener.TxConnectionListener$TransactionSynchronization.afterCompletion(TxConnectionListener.java:1028) at org.jboss.jca.core.connectionmanager.transaction.TransactionSynchronizer.invokeAfter(TransactionSynchronizer.java:397) at org.jboss.jca.core.connectionmanager.transaction.TransactionSynchronizer.afterCompletion(TransactionSynchronizer.java:343) at org.jboss.jca.core.tx.vts.TransactionImpl.finish(TransactionImpl.java:402) at org.jboss.jca.core.tx.vts.TransactionImpl.commit(TransactionImpl.java:99) at org.jboss.jca.core.tx.vts.TxRegistry.commitTransaction(TxRegistry.java:79) at org.jboss.jca.core.tx.vts.UserTransactionImpl.commit(UserTransactionImpl.java:115) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testBase(AcrossTransactionTestCase.java:199) at org.jboss.jca.core.connectionmanager.listener.AcrossTransactionTestCase.testXA(AcrossTransactionTestCase.java:254)