The SessionHandleState class (package com.atomikos.datasource.xa.session) tracks the XA enlistment history of a JDBC or JMS connection/session handle. This class is used in packages com.atomikos.jdbc and com.atomikos.jms to enlist and delist JDBC and JMS connections.
The class diagram is shown below. The SessionHandleState can detect (and deal with) connection/session objects passing transaction boundaries (e.g., when passed as an argument to a method whose transaction attribute specifies REQUIRES_NEW). It does this by tracking all transaction contexts it detects. Each detected context has a TransactionContext instance with internal state transitions for enlistment/delistment of the corresponding XA branch. Note that for most uses, there will only be one TransactionContext.
State changes are detected via one of the notify methods. It is the responsibility of the resource adapter to call these methods when appropriate.
The most important method with respect to reusability in the pool is isReleased: once this returns true, all pending transactions on the session are terminated, and the session handle itself was closed by the application.
SessionHandleState State Transitions
Conceptually, the SessionHandleState objects react according to the following finite state diagram.
- Released: when the session is in this state it has no pending transactions nor does it have any open connection handles. This means that the underlying xa session/connection object can be either pooled or destroyed, whichever is more appropriate. This is by far the most important externally visible state.
- InUse: the session enters this state once it is borrowed from the pool. In this state, the application can supply application-specific work within the scope of a transaction.
- Erroneous: this state is reached after application-level errors on the session where detected. The session should not be reused in the pool and should be destroyed instead.
- Closed: this state is entered when the application has closed the corresponding session handle. This means that the session will no longer receive application-specific work. Note that the transaction(s) that the session was used in may still need to terminate, so the pool should not yet reuse nor destroy this instance. When all transactions are terminated (detected by notifyTransactionTerminated calls), the session transitions to the Released state.
TransactionContext State Transitions
The SessionHandleState objects maintain a TransactionContext object for each transaction detected on the borrow cycle.
The TransactionContext follows the state pattern for modeling its internal state (i.e., are we enlisted, delisted, ...). Each state is expressed via a separate state handler class. The transitions between states are shown below.
Code location of Transitions:
- creation to NotInBranch: ConnectionProxy's constructor: sessionHandleState.notifySessionBorrowed();
- NotInBranch to Terminated: ConnectionProxy's invoke method in check for delistment: sessionHandleState.notifySessionClosed();
- NotInBranch to BranchEnlisted: ConnectionProxy's invoke method in check for enlistment: sessionHandleState.notifyBeforeUse(ct);
- BranchEnlisted to NotInBranch: sessionHandleState.transactionTerminated();
- BranchEnlisted to BranchEnded: ConnectionProxy's JdbcRequeueSynchronization internal class' afterCompletion method: sessionHandleState.notifyTransactionTerminated(compositeTransaction);
- BranchEnded to Terminated: sessionHandleState.transactionTerminated();
- Terminated to end: ?