![JAR search and dependency download from the Maven repository](/logo.png)
org.csc.phynixx.xa.PhynixxManagedXAConnection Maven / Gradle / Ivy
package org.csc.phynixx.xa;
/*
* #%L
* phynixx-xa
* %%
* Copyright (C) 2014 csc
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Arrays;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import org.apache.commons.lang.Validate;
import org.csc.phynixx.common.exceptions.DelegatedRuntimeException;
import org.csc.phynixx.common.exceptions.ExceptionUtils;
import org.csc.phynixx.common.logger.IPhynixxLogger;
import org.csc.phynixx.common.logger.PhynixxLogManager;
import org.csc.phynixx.connection.IPhynixxConnection;
import org.csc.phynixx.connection.IPhynixxManagedConnection;
import org.csc.phynixx.connection.IPhynixxManagedConnectionFactory;
/**
* keeps the XAresource's association to the transactional branch(es) (given via
* XID) or manages the local transaction
*
* @author Christoph Schmidt-Casdorff
*/
class PhynixxManagedXAConnection implements IPhynixxXAConnection {
private static final IPhynixxLogger LOG = PhynixxLogManager.getLogger(PhynixxManagedXAConnection.class);
/**
* parent XAResource
*/
private final PhynixxXAResource xaResource;
private IPhynixxManagedConnectionFactory managedConnectionFactory;
private final ITransactionBinding transactionBinding = new TransactionBinding();
private TransactionManager transactionManager = null;
/**
* Global repository for XA-Branches associated with XAResource of the
* current Resource
*/
private final IXATransactionalBranchRepository xaTransactionalBranchDictionary;
private boolean enlisted;
PhynixxManagedXAConnection(PhynixxXAResource xaResource, TransactionManager transactionManager,
IXATransactionalBranchRepository xaTransactionalBranchDictionary,
IPhynixxManagedConnectionFactory managedConnectionFactory) {
this.xaResource = xaResource;
this.xaTransactionalBranchDictionary = xaTransactionalBranchDictionary;
this.managedConnectionFactory = managedConnectionFactory;
this.transactionManager = transactionManager;
}
@Override
public XAResource getXAResource() {
return xaResource;
}
/**
* Ermittelt, ob zu zugehoeriger Connection bereits ein TX exitiert. This
* tranbsaction binding is reused
*/
@Override
public IPhynixxManagedConnection getManagedConnection() {
// Connection wid in TX eingetragen ....
this.checkTransactionBinding();
return transactionBinding.getManagedConnection();
}
@Override
public C getConnection() {
return this.getManagedConnection().toConnection();
}
/**
* @return !=null if an if the XAConnection is bound to a global transaction
*/
XATransactionalBranch toGlobalTransactionBranch() {
if (this.transactionBinding != null && this.transactionBinding.isGlobalTransaction()) {
GlobalTransactionProxy activeXid = this.transactionBinding.getEnlistedGlobalTransaction();
if (activeXid == null) {
throw new IllegalStateException("No active XABranch");
}
// suche XABranch
return activeXid.getGlobalTransactionalBranch();
}
return null;
}
/**
* @return !=null if an if the XAConnection is bound to a global transaction
*/
LocalTransactionProxy toLocalTransaction() {
if (this.transactionBinding != null && this.transactionBinding.isLocalTransaction()) {
LocalTransactionProxy lid = this.transactionBinding.getEnlistedLocalTransaction();
if (lid == null) {
throw new IllegalStateException("No active LocalTransaction");
}
// suche XABranch
return lid;
}
return null;
}
/**
* call by the XAResource when
* {@link javax.transaction.xa.XAResource#start(javax.transaction.xa.Xid, int)}
* is called. A TransactionalBranch for the given XID ist expected to be
* created.
*
* @param xid
*/
void startTransactionalBranch(Xid xid) {
cleanupTransactionBinding();
final TransactionBindingType transactionBindingType = this.transactionBinding.getTransactionBindingType();
// already associated to a local transaction
if (transactionBindingType == TransactionBindingType.LocalTransaction) {
LocalTransactionProxy localTransactionProxy = this.toLocalTransaction();
Validate.isTrue(!localTransactionProxy.hasTransactionalData(),
"Connection is associated to a local transaction and has uncommitted transactional data");
if (localTransactionProxy.hasTransactionalData()) {
throw new IllegalStateException(
"Connection is associated to a local transaction and has uncommitted transactional data");
}
XATransactionalBranch xaTransactionalBranch =
this.xaTransactionalBranchDictionary.findTransactionalBranch(xid);
// xaTransactionalBranch!=null => joining a existing transactional branch
if (xaTransactionalBranch == null) {
IPhynixxManagedConnection connection = localTransactionProxy.getConnection();
if( connection==null || connection.isClosed()) {
connection= this.createPhysicalConnection();
}
xaTransactionalBranch = this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, connection);
} else {
localTransactionProxy.close();
}
// forget the Local transaction
this.transactionBinding.release();
XATransactionalBranch transactionalBranch = this.xaTransactionalBranchDictionary
.findTransactionalBranch(xid);
Validate.isTrue(xaTransactionalBranch != null, "Expect a transactional branch to be created");
this.transactionBinding.activateGlobalTransaction(new GlobalTransactionProxy(transactionalBranch));
// no transaction binding
} else if (transactionBindingType == TransactionBindingType.NoTransaction) {
XATransactionalBranch transactionalBranch = this.xaTransactionalBranchDictionary
.findTransactionalBranch(xid);
// / xaTransactionalBranch!=null => joining a existing transactional
// branch
if (transactionalBranch == null) {
IPhynixxManagedConnection physicalConnection = this.createPhysicalConnection();
transactionalBranch = this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid,
physicalConnection);
this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, physicalConnection);
}
this.transactionBinding.activateGlobalTransaction(new GlobalTransactionProxy(transactionalBranch));
// if bound to a global TX , check if same XID
} else if (transactionBindingType == TransactionBindingType.GlobalTransaction) {
XATransactionalBranch transactionalBranch = this.xaTransactionalBranchDictionary
.findTransactionalBranch(xid);
// xaTransactionalBranch!=null => joining a existing transactional
// branch
if (transactionalBranch == null) {
IPhynixxManagedConnection physicalConnection = this.createPhysicalConnection();
transactionalBranch = this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid,
physicalConnection);
this.xaTransactionalBranchDictionary.instanciateTransactionalBranch(xid, physicalConnection);
}
// Check if previous XID are compatible to the current
GlobalTransactionProxy previousGlobalTransactionProxy = this.transactionBinding
.getEnlistedGlobalTransaction();
if (previousGlobalTransactionProxy != null) {
Xid previousXid = previousGlobalTransactionProxy.getXid();
byte[] currentTransactionId = previousXid.getGlobalTransactionId();
if (!Arrays.equals(xid.getGlobalTransactionId(), currentTransactionId)) {
LOG.warn("TransactionId of the new Transaction doenn't corresponds to the transactionId of the previous Ids");
}
previousGlobalTransactionProxy.release();
}
this.transactionBinding.activateGlobalTransaction(new GlobalTransactionProxy(transactionalBranch));
}
}
private void cleanupTransactionBinding() {
// cleanup
if (this.transactionBinding.getTransactionBindingType() == TransactionBindingType.LocalTransaction) {
LocalTransactionProxy localTransactionProxy = this.transactionBinding.getEnlistedLocalTransaction();
if (localTransactionProxy != null) {
if (localTransactionProxy.isClosed()) {
localTransactionProxy.release();
}
}
}
}
private IPhynixxManagedConnection createPhysicalConnection() {
return this.managedConnectionFactory.getManagedConnection();
}
void resumeTransactionalBranch(Xid xid) {
this.cleanupTransactionBinding();
TransactionBindingType transactionBindingType = this.transactionBinding.getTransactionBindingType();
if (transactionBindingType == TransactionBindingType.GlobalTransaction) {
throw new IllegalStateException("XAConnection associated to a global transaction and can not be resumed");
}
XATransactionalBranch transactionalBranch = findTransactionalBranch(xid);
transactionalBranch.resume();
// Check if previous XID are compatible to the current
if (transactionBinding.isGlobalTransaction()) {
GlobalTransactionProxy previousGlobalTransactionProxy = this.transactionBinding.getEnlistedGlobalTransaction();
LOG.warn("Resume meets an unrelease Transactional branch. It is released");
previousGlobalTransactionProxy.close();
}
this.transactionBinding.activateGlobalTransaction(new GlobalTransactionProxy(transactionalBranch));
}
private XATransactionalBranch findTransactionalBranch(Xid xid) {
XATransactionalBranch transactionalBranch = this.xaTransactionalBranchDictionary
.findTransactionalBranch(xid);
if (transactionalBranch == null) {
throw new IllegalStateException("No suspended branch for XID " + xid);
}
return transactionalBranch;
}
void suspendTransactionalBranch(Xid xid) {
this.cleanupTransactionBinding();
GlobalTransactionProxy previousGlobalTransactionProxy = this.transactionBinding
.getEnlistedGlobalTransaction();
if (previousGlobalTransactionProxy == null) {
LOG.warn("suspends meets not active Transactional branch.");
} else {
previousGlobalTransactionProxy.release();
}
XATransactionalBranch transactionalBranch = findTransactionalBranch(xid);
transactionalBranch.suspend();
delistTransaction();
}
void joinTransactionalBranch(Xid xid) {
cleanupTransactionBinding();
TransactionBindingType transactionBindingType = this.transactionBinding.getTransactionBindingType();
if (transactionBindingType == TransactionBindingType.GlobalTransaction) {
throw new IllegalStateException(
"XAConnection already associated to a global transaction and can not be joined to XID " + xid);
}
this.transactionBinding.release();
}
/**
* call by the XCAResource when
* {@link javax.transaction.xa.XAResource#end(javax.transaction.xa.Xid, int)}
* is called
*
* @param xid
*/
void closeTransactionalBranch(Xid xid) {
if (this.transactionBinding.getTransactionBindingType() != TransactionBindingType.GlobalTransaction) {
throw new IllegalStateException("XAConnection not associated to a global transaction");
}
GlobalTransactionProxy globalTransactionProxy = this.transactionBinding.getEnlistedGlobalTransaction();
globalTransactionProxy.close();
delistTransaction();
}
@Override
public void close() {
this.xaResource.close();
}
void doClose() {
if(LOG.isDebugEnabled()) {
LOG.debug("Closing "+this);
}
if (this.transactionBinding != null) {
this.transactionBinding.close();
}
this.enlisted=false;
}
private void delistTransaction() {
if (this.transactionBinding != null) {
this.transactionBinding.release();
}
this.enlisted=false;
this.transactionBinding.release();
}
boolean isInGlobalTransaction() {
try {
return transactionManager != null && this.transactionManager.getTransaction() != null;
} catch (SystemException e) {
throw new DelegatedRuntimeException(e);
}
}
/**
* if necessary the current xa resource is enlisted in the current TX.
* The enlistment calls the
* {@link javax.transaction.xa.XAResource#start(javax.transaction.xa.Xid, int)}
* . This call associates the Xid with the current instance
*/
private void enlistTransaction() {
this.cleanupTransactionBinding();
TransactionBindingType transactionBindingType = this.transactionBinding.getTransactionBindingType();
// not associated to global transaction, try to associate a global
// transaction
if (this.isInGlobalTransaction() && transactionBindingType != TransactionBindingType.GlobalTransaction) {
try {
Transaction ntx = this.transactionManager.getTransaction();
// Bitronix calls start on reaction of enlist --- check if cycle
if (!enlisted && ntx != null) {
this.enlisted = true;
// enlisted makes startTransaactionalBranch calling
this.enlisted = ntx.enlistResource(this.xaResource);
if (!enlisted) {
LOG.error("Enlisting " + xaResource + " failed");
} else {
}
} else {
LOG.debug("SampleXAConnection:connectionRequiresTransaction (no globalTransaction found)");
}
} catch (RollbackException n) {
LOG.error("SampleXAConnection:prevokeAction enlistResource exception : " + n.toString());
} catch (SystemException n) {
LOG.error("SampleXAConnection:connectionRequiresTransaction " + n + "\n"
+ ExceptionUtils.getStackTrace(n));
throw new DelegatedRuntimeException(n);
}
} else if (transactionBindingType == TransactionBindingType.NoTransaction) {
this.transactionBinding.activateLocalTransaction(new LocalTransactionProxy(this.managedConnectionFactory
.getManagedConnection()));
} else { // In Global Transaction and associated to a global transaction
// => nothing to do
if (this.isInGlobalTransaction() && transactionBindingType == TransactionBindingType.GlobalTransaction) {
// Not in Global Transaction and associated to a local
// transaction => nothing to do
} else if (!this.isInGlobalTransaction()
&& transactionBindingType == TransactionBindingType.LocalTransaction) {
}
}
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
PhynixxManagedXAConnection that = (PhynixxManagedXAConnection) o;
return xaResource.equals(that.xaResource);
}
@Override
public int hashCode() {
return xaResource.hashCode();
}
@Override
public String toString() {
return "PhynixxManagedXAConnection{" + "xaResource=" + xaResource + ", transactionBinding="
+ this.transactionBinding + '}';
}
void checkTransactionBinding() {
if (this.isInGlobalTransaction()) {
this.enlistTransaction();
}
if (this.transactionBinding == null
|| this.transactionBinding.getTransactionBindingType() == TransactionBindingType.NoTransaction) {
this.transactionBinding.activateLocalTransaction(new LocalTransactionProxy(this.createPhysicalConnection()) );
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy