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.TransactionManagerImp Maven / Gradle / Ivy
/**
* Copyright (C) 2000-2023 Atomikos
*
* LICENSE CONDITIONS
*
* See http://www.atomikos.com/Main/WhichLicenseApplies for details.
*/
package com.atomikos.icatch.jta;
import java.util.HashMap;
import java.util.Map;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.StringRefAddr;
import javax.transaction.InvalidTransactionException;
import javax.transaction.NotSupportedException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.CompositeTransactionManager;
import com.atomikos.icatch.SubTxAwareParticipant;
import com.atomikos.icatch.SysException;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.recovery.TxState;
/**
* The main JTA transaction manager singleton.
*/
public class TransactionManagerImp implements TransactionManager,
SubTxAwareParticipant, Referenceable, UserTransaction
{
private static final Logger LOGGER = LoggerFactory.createLogger(TransactionManagerImp.class);
/**
* Transaction property name to indicate that the transaction is a
* JTA transaction. If this property is set to an arbitrary non-null
* value then a JTA transaction is assumed by this class.
* This property is used for detecting incompatible existing transactions:
* if a transaction exists without this property then the begin method
* will suspend it (and resume afterwards).
*/
public static final String JTA_PROPERTY_NAME = "com.atomikos.icatch.jta.transaction";
private static TransactionManagerImp singleton = null;
private static int defaultTimeoutInSecondsForNewTransactions;
private static boolean jtaTransactionsAreSerialByDefault = false;
private ThreadLocal timeoutInSecondsForNewTransactions = new ThreadLocal() {
protected Integer initialValue() {
return defaultTimeoutInSecondsForNewTransactions;
};
};
private Map jtaTransactionToCoreTransactionMap;
private CompositeTransactionManager compositeTransactionManager;
private static final void raiseNoTransaction()
{
StringBuffer msg = new StringBuffer();
msg.append ( "This method needs a transaction for the calling thread and none exists.\n" );
msg.append ( "Possible causes: either you didn't start a transaction,\n" );
msg.append ( "it rolledback due to timeout, or it was committed already.\n" );
msg.append ( "ACTIONS: You can try one of the following: \n" );
msg.append ( "1. Make sure you started a transaction for the thread.\n" );
msg.append ( "2. Make sure you didn't terminate it yet.\n" );
msg.append ( "3. Increase the transaction timeout to avoid automatic rollback of long transactions;\n" );
msg.append ( " check http://www.atomikos.com/Documentation/JtaProperties for how to do this." );
LOGGER.logWarning ( msg.toString() );
throw new IllegalStateException ( msg.toString() );
}
/**
* Sets the default serial mode for new txs.
*
* @param value
* If true, then new txs will be set to serial mode.
*/
public static void setDefaultSerial ( boolean value )
{
jtaTransactionsAreSerialByDefault = value;
}
/**
* Gets the default mode for new txs.
*
* @return boolean If true, then new txs started through here will be in
* serial mode.
*/
public static boolean getDefaultSerial ()
{
return jtaTransactionsAreSerialByDefault;
}
/**
* Set the default transaction timeout value.
*
* @param defaultTimeoutValueInSeconds
* the default transaction timeout value in seconds.
*/
public static void setDefaultTimeout ( int defaultTimeoutValueInSeconds )
{
defaultTimeoutInSecondsForNewTransactions = defaultTimeoutValueInSeconds;
}
/**
* Get the default timeout value.
*
* @return the default transaction timeout value in seconds.
*/
public static int getDefaultTimeout ()
{
return defaultTimeoutInSecondsForNewTransactions;
}
/**
* Install a transaction manager.
*
* @param ctm
* The composite transaction manager to use.
* @param automaticResourceRegistration
* If true, then unknown XAResource instances should lead to the
* addition of a new temporary resource. If false, then unknown
* resources will lead to an exception.
*
*/
public static synchronized void installTransactionManager (
CompositeTransactionManager ctm)
{
if ( ctm != null ) {
singleton = new TransactionManagerImp(ctm);
} else {
singleton = null;
}
}
/**
* Gets the installed transaction manager, if any.
*
* @return TransactionManager The installed instance, null if none.
*/
public static TransactionManager getTransactionManager ()
{
return singleton;
}
private TransactionManagerImp(CompositeTransactionManager ctm)
{
compositeTransactionManager = ctm;
jtaTransactionToCoreTransactionMap = new HashMap();
}
private void addToMap ( String tid , TransactionImp tx )
{
synchronized ( jtaTransactionToCoreTransactionMap ) {
jtaTransactionToCoreTransactionMap.put ( tid , tx );
}
}
private void removeFromMap ( String tid )
{
synchronized ( jtaTransactionToCoreTransactionMap ) {
jtaTransactionToCoreTransactionMap.remove ( tid );
}
}
/**
* @return TransactionImp The relevant instance, or null.
*/
TransactionImp getJtaTransactionWithId ( String tid )
{
synchronized ( jtaTransactionToCoreTransactionMap ) {
return jtaTransactionToCoreTransactionMap.get ( tid );
}
}
private CompositeTransaction getCompositeTransaction() throws ExtendedSystemException
{
CompositeTransaction ct = null;
try {
ct = compositeTransactionManager.getCompositeTransaction ();
} catch ( SysException se ) {
String msg = "Error while retrieving the transaction for the calling thread";
LOGGER.logError( msg , se);
throw new ExtendedSystemException ( msg , se );
}
establishJtaTransactionContextIfNecessary(ct);
return ct;
}
private void establishJtaTransactionContextIfNecessary(
CompositeTransaction ct) {
if ( isJtaTransaction(ct) ) {
TransactionImp jtaTransaction = getJtaTransactionWithId ( ct.getTid () );
if ( jtaTransaction == null ) {
recreateCompositeTransactionAsJtaTransaction(ct);
}
}
}
/**
* Gets any previous transaction with the given identifier.
*
* @return Transaction The instance, or null if not found.
*/
public Transaction getTransaction ( String tid )
{
return getJtaTransactionWithId ( tid );
}
/**
* Creates a new transaction and associate it with the current thread. If the
* current thread already has a transaction, then a local subtransaction
* will be created.
*/
public void begin () throws NotSupportedException, SystemException
{
begin ( getTransactionTimeout() );
}
/**
* Custom begin to guarantee a timeout value through an argument.
*/
public void begin ( int timeout ) throws NotSupportedException,
SystemException
{
CompositeTransaction ct = null;
ResumePreviousTransactionSubTxAwareParticipant resumeParticipant = null;
ct = compositeTransactionManager.getCompositeTransaction();
if ( ct != null && ct.getProperty ( JTA_PROPERTY_NAME ) == null ) {
LOGGER.logWarning ( "JTA: temporarily suspending incompatible transaction: " + ct.getTid() +
" (will be resumed after JTA transaction ends)" );
ct = compositeTransactionManager.suspend();
resumeParticipant = new ResumePreviousTransactionSubTxAwareParticipant ( ct );
}
try {
ct = compositeTransactionManager.createCompositeTransaction ( ( ( long ) timeout ) * 1000 );
if ( resumeParticipant != null ) ct.addSubTxAwareParticipant ( resumeParticipant );
if(ct.isRoot() && timeout != defaultTimeoutInSecondsForNewTransactions) {
ct.addSubTxAwareParticipant(new SubTxAwareParticipant() {
@Override
public void rolledback(CompositeTransaction transaction) {
timeoutInSecondsForNewTransactions.set(defaultTimeoutInSecondsForNewTransactions);
}
@Override
public void committed(CompositeTransaction transaction) {
timeoutInSecondsForNewTransactions.set(defaultTimeoutInSecondsForNewTransactions);
}
});
}
if ( ct.isRoot () && getDefaultSerial () )
ct.setSerial ();
markAsJtaTransaction(ct);
} catch ( SysException se ) {
String msg = "Error in begin()";
LOGGER.logError( msg , se );
throw new ExtendedSystemException ( msg , se );
}
recreateCompositeTransactionAsJtaTransaction(ct);
}
public static void markAsJtaTransaction(CompositeTransaction ct) {
ct.setProperty ( JTA_PROPERTY_NAME , "true" );
}
/**
* @see javax.transaction.TransactionManager
*/
public Transaction getTransaction () throws SystemException
{
TransactionImp ret = null;
CompositeTransaction ct = getCompositeTransaction();
if ( ct != null) ret = getJtaTransactionWithId ( ct.getTid () );
return ret;
}
private TransactionImp recreateCompositeTransactionAsJtaTransaction(
CompositeTransaction ct) {
TransactionImp ret = null;
if (ct.getState ().equals ( TxState.ACTIVE )) { // setRollbackOnly may have been called!
ret = new TransactionImp(ct);
addToMap ( ct.getTid (), ret );
ct.addSubTxAwareParticipant ( this );
}
return ret;
}
public static boolean isJtaTransaction(CompositeTransaction ct) {
boolean ret = false;
if (ct !=null && ct.getProperty( JTA_PROPERTY_NAME ) != null) ret = true;
return ret;
}
/**
* @see javax.transaction.TransactionManager
*/
public void setTransactionTimeout ( int seconds ) throws SystemException
{
if ( seconds > 0 ) {
timeoutInSecondsForNewTransactions.set(seconds);
} else if ( seconds == 0 ) {
timeoutInSecondsForNewTransactions.set(defaultTimeoutInSecondsForNewTransactions);
} else {
String msg = "setTransactionTimeout: value must be >= 0";
LOGGER.logWarning( msg );
throw new SystemException ( msg );
}
}
public int getTransactionTimeout ()
{
return timeoutInSecondsForNewTransactions.get();
}
/**
* @see javax.transaction.TransactionManager
*/
public Transaction suspend() throws SystemException
{
TransactionImp ret = (TransactionImp) getTransaction();
if ( ret != null ) {
suspendUnderlyingCompositeTransaction();
ret.suspendEnlistedXaResources(); // cf case 61305
}
return ret;
}
private void suspendUnderlyingCompositeTransaction()
throws ExtendedSystemException {
try {
compositeTransactionManager.suspend();
} catch ( SysException se ) {
String msg = "Unexpected error while suspending the existing transaction for the current thread";
LOGGER.logError( msg , se );
throw new ExtendedSystemException ( msg , se );
}
}
/**
* @see javax.transaction.TransactionManager
*/
public void resume ( Transaction tobj ) throws InvalidTransactionException,
IllegalStateException, SystemException
{
if ( tobj == null || !(tobj instanceof TransactionImp) ) {
String msg = "The specified transaction object is invalid for this configuration: " + tobj;
LOGGER.logWarning( msg );
throw new InvalidTransactionException ( msg );
}
TransactionImp tximp = (TransactionImp) tobj;
try {
compositeTransactionManager.resume ( tximp.getCT () );
} catch ( SysException se ) {
String msg = "Unexpected error while resuming the transaction in the calling thread";
LOGGER.logError( msg , se );
throw new ExtendedSystemException(msg , se );
}
tximp.resumeEnlistedXaReources();
}
/**
* @see javax.transaction.TransactionManager
*/
public int getStatus() throws SystemException
{
int ret = Status.STATUS_NO_TRANSACTION;
Transaction tx = getTransaction();
if ( tx == null ) {
ret = Status.STATUS_NO_TRANSACTION;
} else {
ret = tx.getStatus ();
}
return ret;
}
/**
* @see javax.transaction.TransactionManager
*/
public void commit () throws javax.transaction.RollbackException,
javax.transaction.HeuristicMixedException,
javax.transaction.HeuristicRollbackException,
javax.transaction.SystemException, java.lang.IllegalStateException,
java.lang.SecurityException
{
Transaction tx = getTransaction();
if ( tx == null ) raiseNoTransaction();
tx.commit();
}
/**
* @see javax.transaction.TransactionManager
*/
public void rollback () throws IllegalStateException, SystemException,
SecurityException
{
Transaction tx = getTransaction();
if ( tx == null ) raiseNoTransaction();
tx.rollback();
}
/**
* @see javax.transaction.TransactionManager
*/
public void setRollbackOnly () throws IllegalStateException,
SystemException
{
Transaction tx = getTransaction();
if ( tx == null ) raiseNoTransaction();
try {
tx.setRollbackOnly ();
} catch ( SecurityException se ) {
String msg = "Unexpected error during setRollbackOnly";
LOGGER.logError( msg , se );
throw new ExtendedSystemException ( msg, se );
}
}
/**
* @see com.atomikos.icatch.SubTxAwareParticipant
*/
public void committed ( CompositeTransaction tx )
{
removeFromMap ( tx.getTid () );
}
/**
* @see com.atomikos.icatch.SubTxAwareParticipant
*/
public void rolledback ( CompositeTransaction tx )
{
removeFromMap ( tx.getTid () );
}
/**
* @see javax.naming.Referenceable#getReference()
*/
public Reference getReference () throws NamingException
{
return new Reference ( getClass ().getName (), new StringRefAddr (
"name", "TransactionManager" ), TransactionManagerFactory.class
.getName (), null );
}
}