All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.atomikos.icatch.jta.TransactionImp Maven / Gradle / Ivy
/**
* Copyright (C) 2000-2020 Atomikos
*
* LICENSE CONDITIONS
*
* See http://www.atomikos.com/Main/WhichLicenseApplies for details.
*/
package com.atomikos.icatch.jta;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import com.atomikos.datasource.RecoverableResource;
import com.atomikos.datasource.ResourceException;
import com.atomikos.datasource.TransactionalResource;
import com.atomikos.datasource.xa.XAResourceTransaction;
import com.atomikos.datasource.xa.XATransactionalResource;
import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.HeurHazardException;
import com.atomikos.icatch.HeurMixedException;
import com.atomikos.icatch.SysException;
import com.atomikos.icatch.config.Configuration;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.recovery.TxState;
/**
* Implementation of the javax.transaction.Transaction interface.
*/
class TransactionImp implements Transaction {
private static final Logger LOGGER = LoggerFactory
.createLogger(TransactionImp.class);
private static void rethrowAsJtaRollbackException(String msg, Throwable cause)
throws javax.transaction.RollbackException {
javax.transaction.RollbackException ret = new javax.transaction.RollbackException(
msg);
ret.initCause(cause);
throw ret;
}
private static void rethrowAsJtaHeuristicMixedException(String msg, Throwable cause)
throws javax.transaction.HeuristicMixedException {
javax.transaction.HeuristicMixedException ret = new javax.transaction.HeuristicMixedException(
msg);
ret.initCause(cause);
throw ret;
}
private static void rethrowAsJtaHeuristicRollbackException(String msg,
Throwable cause)
throws javax.transaction.HeuristicRollbackException {
javax.transaction.HeuristicRollbackException ret = new javax.transaction.HeuristicRollbackException(
msg);
ret.initCause(cause);
throw ret;
}
private CompositeTransaction compositeTransaction;
private Map xaResourceToResourceTransactionMap_;
TransactionImp(CompositeTransaction ct) {
this.compositeTransaction = ct;
this.xaResourceToResourceTransactionMap_ = new HashMap();
}
CompositeTransaction getCT() {
return this.compositeTransaction;
}
private synchronized void addXAResourceTransaction(
XAResourceTransaction restx, XAResource xares) {
this.xaResourceToResourceTransactionMap_.put(new XAResourceKey(xares),
restx);
}
private void assertActiveOrSuspended(XAResourceTransaction restx) {
if (!(restx.isActive() || restx.isXaSuspended())) {
LOGGER.logWarning("Unexpected resource transaction state for " + restx);
}
}
private synchronized XAResourceTransaction findXAResourceTransaction(
XAResource xares) {
XAResourceTransaction ret = null;
ret = this.xaResourceToResourceTransactionMap_.get(new XAResourceKey(
xares));
if (ret != null)
assertActiveOrSuspended(ret);
return ret;
}
private synchronized void removeXAResourceTransaction(XAResource xares) {
this.xaResourceToResourceTransactionMap_
.remove(new XAResourceKey(xares));
}
/**
* @see javax.transaction.Transaction
*/
@Override
public void registerSynchronization(javax.transaction.Synchronization s)
throws java.lang.IllegalStateException,
javax.transaction.SystemException {
try {
Sync2Sync adaptor = new Sync2Sync(s);
this.compositeTransaction.registerSynchronization(adaptor);
} catch (SysException se) {
String msg = "Unexpected error during registerSynchronization";
LOGGER.logWarning(msg, se);
throw new ExtendedSystemException(msg, se);
}
}
/**
* @see javax.transaction.Transaction
*/
@Override
public int getStatus() {
TxState state = this.compositeTransaction.getState();
switch (state) {
case IN_DOUBT:
return Status.STATUS_PREPARED;
case PREPARING:
return Status.STATUS_PREPARING;
case ACTIVE:
return Status.STATUS_ACTIVE;
case MARKED_ABORT:
return Status.STATUS_MARKED_ROLLBACK;
case COMMITTING:
return Status.STATUS_COMMITTING;
case ABORTING:
return Status.STATUS_ROLLING_BACK;
case COMMITTED:
return Status.STATUS_COMMITTED;
case ABORTED:
return Status.STATUS_ROLLEDBACK;
default:
return Status.STATUS_UNKNOWN;
}
}
/**
* @see javax.transaction.Transaction.
*/
@Override
public void commit() throws javax.transaction.RollbackException,
javax.transaction.HeuristicMixedException,
javax.transaction.HeuristicRollbackException,
javax.transaction.SystemException, java.lang.SecurityException {
try {
this.compositeTransaction.commit();
} catch (HeurHazardException hh) {
rethrowAsJtaHeuristicMixedException(hh.getMessage(), hh);
} catch (HeurMixedException hm) {
rethrowAsJtaHeuristicMixedException(hm.getMessage(), hm);
} catch (SysException se) {
LOGGER.logError(se.getMessage(), se);
throw new ExtendedSystemException(se.getMessage(), se);
} catch (com.atomikos.icatch.RollbackException rb) {
// see case 29708: all statements have been closed
String msg = rb.getMessage();
Throwable cause = rb.getCause();
if (cause == null)
cause = rb;
rethrowAsJtaRollbackException(msg, cause);
}
}
/**
* @see javax.transaction.Transaction.
*/
@Override
public void rollback() throws IllegalStateException, SystemException {
try {
this.compositeTransaction.rollback();
} catch (SysException se) {
LOGGER.logError(se.getMessage(), se);
throw new ExtendedSystemException(se.getMessage(), se);
}
}
/**
* @see javax.transaction.Transaction.
*/
@Override
public void setRollbackOnly() throws IllegalStateException, SystemException {
this.compositeTransaction.setRollbackOnly();
}
/**
* @see javax.transaction.Transaction.
*/
@Override
public boolean enlistResource(XAResource xares)
throws javax.transaction.RollbackException,
javax.transaction.SystemException, IllegalStateException {
TransactionalResource res = null;
XAResourceTransaction restx = null;
int status = getStatus();
switch (status) {
case Status.STATUS_MARKED_ROLLBACK:
case Status.STATUS_ROLLEDBACK:
case Status.STATUS_ROLLING_BACK:
String msg = "Transaction rollback - enlisting more resources is useless.";
LOGGER.logWarning(msg);
throw new javax.transaction.RollbackException(msg);
case Status.STATUS_COMMITTED:
case Status.STATUS_PREPARED:
case Status.STATUS_UNKNOWN:
msg = "Enlisting more resources is no longer permitted: transaction is in state "
+ this.compositeTransaction.getState();
LOGGER.logWarning(msg);
throw new IllegalStateException(msg);
}
XAResourceTransaction suspendedXAResourceTransaction = findXAResourceTransaction(xares);
if (suspendedXAResourceTransaction != null) {
if (!suspendedXAResourceTransaction.isXaSuspended()) {
String msg = "The given XAResource instance is being enlisted a second time without delist in between?";
LOGGER.logWarning(msg);
throw new IllegalStateException(msg);
}
// note: for suspended XAResources, the lookup MUST SUCCEED
// since the TMRESUME must be called on the SAME XAResource
// INSTANCE, and lookup also works on the instance level
try {
suspendedXAResourceTransaction.setXAResource(xares);
suspendedXAResourceTransaction.xaResume();
} catch (XAException xaerr) {
if (XAException.XA_RBBASE <= xaerr.errorCode
&& xaerr.errorCode <= XAException.XA_RBEND)
rethrowAsJtaRollbackException(
"Transaction was already rolled back inside the back-end resource. Further enlists are useless.",
xaerr);
throw new ExtendedSystemException(
"Unexpected error during enlist", xaerr);
}
} else {
res = findRecoverableResourceForXaResource(xares);
if (LOGGER.isDebugEnabled()) {
LOGGER.logDebug("enlistResource ( " + xares
+ " ) with transaction " + toString());
}
if (res == null) {
String msg = "There is no registered resource that can recover the given XAResource instance. "
+ "\n"
+ "Please register a corresponding resource first.";
LOGGER.logWarning(msg);
throw new javax.transaction.SystemException(msg);
}
try {
restx = (XAResourceTransaction) res
.getResourceTransaction(this.compositeTransaction);
// next, we MUST set the xa resource again,
// because ONLY the instance we got as argument
// is available for use now !
// older instances (set in restx from previous sibling)
// have connections that may be in reuse already
// ->old xares not valid except for 2pc operations
restx.setXAResource(xares);
restx.resume();
} catch (ResourceException re) {
throw new ExtendedSystemException(
"Unexpected error during enlist", re);
} catch (RuntimeException e) {
throw e;
}
addXAResourceTransaction(restx, xares);
}
return true;
}
private TransactionalResource findRecoverableResourceForXaResource(
XAResource xares) {
TransactionalResource ret = null;
XATransactionalResource xatxres;
synchronized (Configuration.class) {
// synchronized to avoid case 61740 and 142795
Collection resources = Configuration.getResources();
for (RecoverableResource rres : resources) {
if (rres instanceof XATransactionalResource) {
xatxres = (XATransactionalResource) rres;
if (xatxres.usesXAResource(xares))
ret = xatxres;
}
}
}
return ret;
}
/**
* @see javax.transaction.Transaction.
*/
@Override
public boolean delistResource(XAResource xares, int flag)
throws java.lang.IllegalStateException,
javax.transaction.SystemException {
if (LOGGER.isDebugEnabled()) {
LOGGER.logDebug("delistResource ( " + xares + " ) with transaction "
+ toString());
}
XAResourceTransaction active = findXAResourceTransaction(xares);
// NOTE: the lookup MUST have succeeded since the delist must be
// done by the same XAResource INSTANCE as the enlist before,
// and lookup also uses instance comparison.
if (active == null) {
String msg = "Illegal attempt to delist an XAResource instance that was not previously enlisted.";
LOGGER.logWarning(msg);
throw new IllegalStateException(msg);
}
if (flag == XAResource.TMSUCCESS || flag == XAResource.TMFAIL) {
try {
active.suspend();
} catch (ResourceException re) {
throw new ExtendedSystemException(
"Error in delisting the given XAResource", re);
}
removeXAResourceTransaction(xares);
if (flag == XAResource.TMFAIL)
setRollbackOnly();
} else if (flag == XAResource.TMSUSPEND) {
try {
active.xaSuspend();
} catch (XAException xaerr) {
throw new ExtendedSystemException(
"Error in delisting the given XAResource", xaerr);
}
} else {
String msg = "Unknown delist flag: " + flag;
LOGGER.logWarning(msg);
throw new javax.transaction.SystemException(msg);
}
return true;
}
/**
* Compares to another object.
*
* @param o
* The other object to compare to.
*
* @return boolean True iff the underlying tx is the same.
*/
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof TransactionImp))
return false;
TransactionImp other = (TransactionImp) o;
return this.compositeTransaction.isSameTransaction(other.compositeTransaction);
}
/**
* Computes a hash value for the object.
*
* @return int The hash value.
*/
@Override
public int hashCode() {
return this.compositeTransaction.hashCode();
}
@Override
public String toString() {
return this.compositeTransaction.getTid().toString();
}
void suspendEnlistedXaResources() throws ExtendedSystemException {
// cf case 61305
Iterator xaResourceTransactions = this.xaResourceToResourceTransactionMap_
.values().iterator();
while (xaResourceTransactions.hasNext()) {
XAResourceTransaction resTx = xaResourceTransactions.next();
try {
resTx.xaSuspend();
} catch (XAException e) {
throw new ExtendedSystemException(
"Error in suspending the given XAResource", e);
}
}
}
void resumeEnlistedXaReources() throws ExtendedSystemException {
Iterator xaResourceTransactions = this.xaResourceToResourceTransactionMap_
.values().iterator();
while (xaResourceTransactions.hasNext()) {
XAResourceTransaction resTx = xaResourceTransactions.next();
try {
resTx.xaResume();
xaResourceTransactions.remove();
} catch (XAException e) {
throw new ExtendedSystemException(
"Error in resuming the given XAResource", e);
}
}
}
}