The TxConnectionManager is a JBoss ConnectionManager
implementation for jca adapters implementing LocalTransaction and XAResource support.
It implements a ConnectionEventListener that implements XAResource to
manage transactions through the Transaction Manager. To assure that all
work in a local transaction occurs over the same ManagedConnection, it
includes a xid to ManagedConnection map. When a Connection is requested
or a transaction started with a connection handle in use, it checks to
see if a ManagedConnection already exists enrolled in the global
transaction and uses it if found. Otherwise a free ManagedConnection
has its LocalTransaction started and is used. From the
BaseConnectionManager2, it includes functionality to obtain managed
connections from
a ManagedConnectionPool mbean, find the Subject from a SubjectSecurityDomain,
and interact with the CachedConnectionManager for connections held over
transaction and method boundaries. Important mbean references are to a
ManagedConnectionPool supplier (typically a JBossManagedConnectionPool), and a
RARDeployment representing the ManagedConnectionFactory.
This connection manager has to perform the following operations:
1. When an application component requests a new ConnectionHandle,
it must find a ManagedConnection, and make sure a
ConnectionEventListener is registered. It must inform the
CachedConnectionManager that a connection handle has been given
out. It needs to count the number of handles for each
ManagedConnection. If there is a current transaction, it must
enlist the ManagedConnection's LocalTransaction in the transaction
using the ConnectionEventListeners XAResource XAResource implementation.
Entry point: ConnectionManager.allocateConnection.
written.
2. When a ConnectionClosed event is received from the
ConnectionEventListener, it must reduce the handle count. If
the handle count is zero, the XAResource should be delisted from
the Transaction, if any. The CachedConnectionManager must be
notified that the connection is closed.
Entry point: ConnectionEventListener.ConnectionClosed.
written
3. When a transaction begun notification is received from the
UserTransaction (via the CachedConnectionManager, all
managedConnections associated with the current object must be
enlisted in the transaction.
Entry point: (from
CachedConnectionManager)
ConnectionCacheListener.transactionStarted(Transaction,
Collection). The collection is of ConnectionRecord objects.
written.
5. When an "entering object" notification is received from the
CachedConnectionInterceptor, all the connections for the current
object must be associated with a ManagedConnection. if there is a
Transaction, the XAResource must be enlisted with it.
Entry point: ConnectionCacheListener.reconnect(Collection conns) The Collection
is of ConnectionRecord objects.
written.
6. When a "leaving object" notification is received from the
CachedConnectionInterceptor, all the managedConnections for the
current object must have their XAResources delisted from the
current Transaction, if any, and cleanup called on each
ManagedConnection.
Entry point: ConnectionCacheListener.disconnect(Collection conns).
written.
| Method from org.jboss.resource.connectionmanager.TxConnectionManager Detail: |
public void checkTransactionActive() throws SystemException, RollbackException {
if (tm == null)
throw new IllegalStateException("No transaction manager: " + ccmName);
Transaction tx = tm.getTransaction();
if (tx != null)
{
int status = tx.getStatus();
// Only allow states that will actually succeed
if (status != Status.STATUS_ACTIVE && status != Status.STATUS_PREPARING && status != Status.STATUS_PREPARED && status != Status.STATUS_COMMITTING)
throw new RollbackException("Transaction " + tx + " cannot proceed " + TxUtils.getStatusAsString(status));
}
}
|
public ConnectionListener createConnectionListener(ManagedConnection mc,
Object context) throws ResourceException {
XAResource xaResource = null;
if (localTransactions)
{
xaResource = new LocalXAResource(log);
if (xaResourceTimeout != 0)
log.debug("XAResource transaction timeout cannot be set for local transactions: " + getJndiName());
}
else
{
if(wrapXAResource)
{
log.trace("Generating XAResourceWrapper for TxConnectionManager" + this);
xaResource = new XAResourceWrapper(isSameRMOverrideValue, padXid, mc.getXAResource());
}
else
{
log.trace("Not wrapping XAResource.");
xaResource = mc.getXAResource();
}
if (xaResourceTimeout != 0)
{
try
{
if (xaResource.setTransactionTimeout(xaResourceTimeout) == false)
log.debug("XAResource does not support transaction timeout configuration: " + getJndiName());
}
catch (XAException e)
{
throw new JBossResourceException("Unable to set XAResource transaction timeout: " + getJndiName(), e);
}
}
}
ConnectionListener cli = new TxConnectionEventListener(mc, poolingStrategy, context, log, xaResource);
mc.addConnectionEventListener(cli);
return cli;
}
|
public Boolean getIsSameRMOverrideValue() {
return isSameRMOverrideValue;
}
Get the IsSameRMOverrideValue value. |
public ConnectionListener getManagedConnection(Subject subject,
ConnectionRequestInfo cri) throws ResourceException {
Transaction trackByTransaction = null;
try
{
Transaction tx = tm.getTransaction();
if (tx != null && TxUtils.isActive(tx) == false)
throw new ResourceException("Transaction is not active: tx=" + tx);
if (trackConnectionByTx)
trackByTransaction = tx;
}
catch (Throwable t)
{
JBossResourceException.rethrowAsResourceException("Error checking for a transaction.", t);
}
if (trace)
log.trace("getManagedConnection trackByTx=" + trackConnectionByTx + " tx=" + trackByTransaction);
return super.getManagedConnection(trackByTransaction, subject, cri);
}
|
public boolean getPadXid() {
return this.padXid;
}
|
public long getTimeLeftBeforeTransactionTimeout(boolean errorRollback) throws RollbackException {
if (tm == null)
throw new IllegalStateException("No transaction manager: " + ccmName);
if (tm instanceof TransactionTimeoutConfiguration)
return ((TransactionTimeoutConfiguration) tm).getTimeLeftBeforeTransactionTimeout(errorRollback);
return -1;
}
|
public String getTransactionManager() {
return this.tmName;
} Deprecated!
|
public TransactionManager getTransactionManagerInstance() {
return tm;
}
|
public ObjectName getTransactionManagerService() {
return transactionManagerService;
}
|
public boolean getWrapXAResource() {
return wrapXAResource;
}
|
public int getXAResourceTransactionTimeout() {
return xaResourceTimeout;
}
|
public boolean isLocalTransactions() {
return localTransactions;
}
|
public boolean isTrackConnectionByTx() {
return trackConnectionByTx;
}
|
public boolean isTransactional() {
return TxUtils.isCompleted(tm) == false;
}
|
protected void managedConnectionDisconnected(ConnectionListener cl) throws ResourceException {
Throwable throwable = null;
try
{
cl.delist();
}
catch (Throwable t)
{
throwable = t;
}
//if there are no more handles and tx is complete, we can return to pool.
boolean isFree = cl.isManagedConnectionFree();
if (trace)
log.trace("Disconnected isManagedConnectionFree=" + isFree + " cl=" + cl);
if (isFree)
returnManagedConnection(cl, false);
// Rethrow the error
if (throwable != null)
JBossResourceException.rethrowAsResourceException("Could not delist resource, probably a transaction rollback? ", throwable);
}
|
protected void managedConnectionReconnected(ConnectionListener cl) throws ResourceException {
try
{
cl.enlist();
}
catch (Throwable t)
{
if (trace)
log.trace("Could not enlist in transaction on entering meta-aware object! " + cl, t);
throw new JBossResourceException("Could not enlist in transaction on entering meta-aware object!", t);
}
}
|
protected static void rethrowAsSystemException(String context,
Transaction tx,
Throwable t) throws SystemException {
if (t instanceof SystemException)
throw (SystemException) t;
if (t instanceof RuntimeException)
throw (RuntimeException) t;
if (t instanceof Error)
throw (Error) t;
if (t instanceof RollbackException)
throw new IllegalStateException(context + " tx=" + tx + " marked for rollback.");
throw new NestedRuntimeException(context + " tx=" + tx + " got unexpected error ", t);
}
|
public void setIsSameRMOverrideValue(Boolean isSameRMOverrideValue) {
this.isSameRMOverrideValue = isSameRMOverrideValue;
}
Set the IsSameRMOverrideValue value. |
public void setLocalTransactions(boolean localTransactions) {
this.localTransactions = localTransactions;
if (localTransactions)
setTrackConnectionByTx(true);
}
|
public void setPadXid(boolean padXid) {
this.padXid = padXid;
}
|
public void setTrackConnectionByTx(boolean trackConnectionByTx) {
this.trackConnectionByTx = trackConnectionByTx;
}
|
public void setTransactionManager(String tmName) {
this.tmName = tmName;
} Deprecated!
|
public void setTransactionManagerInstance(TransactionManager tm) {
this.tm = tm;
}
|
public void setTransactionManagerService(ObjectName transactionManagerService) {
this.transactionManagerService = transactionManagerService;
}
|
public void setWrapXAResource(boolean useXAWrapper) {
this.wrapXAResource = useXAWrapper;
}
|
public void setXAResourceTransactionTimeout(int timeout) {
this.xaResourceTimeout = timeout;
}
|
protected void startService() throws Exception {
if (transactionManagerService != null)
tm = (TransactionManager)getServer().getAttribute(transactionManagerService, "TransactionManager");
else
{
log.warn("----------------------------------------------------------");
log.warn("----------------------------------------------------------");
log.warn("Please change your datasource setup to use < depends optional-attribute-name\"TransactionManagerService\" >jboss:service=TransactionManager< /depends >");
log.warn("instead of < attribute name=\"TransactionManager\" >java:/TransactionManager< /attribute >");
log.warn("Better still, use a *-ds.xml file");
log.warn("----------------------------------------------------------");
log.warn("----------------------------------------------------------");
tm = (TransactionManager)new InitialContext().lookup(tmName);
}
super.startService();
}
|
protected void stopService() throws Exception {
this.tm = null;
super.stopService();
}
|
public void transactionStarted(Collection crs) throws SystemException {
Set cls = new HashSet();
for (Iterator i = crs.iterator(); i.hasNext(); )
{
ConnectionRecord cr = (ConnectionRecord)i.next();
ConnectionListener cl = cr.cl;
if (!cls.contains(cl))
{
cls.add(cl);
cl.enlist();
}
}
}
|