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.
/*
* JBoss, Home of Professional Open Source
* Copyright 2006, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
* (C) 2005-2006,
* @author JBoss Inc.
*/
package com.arjuna.ats.jbossatx;
import jakarta.transaction.HeuristicMixedException;
import jakarta.transaction.HeuristicRollbackException;
import jakarta.transaction.InvalidTransactionException;
import jakarta.transaction.NotSupportedException;
import jakarta.transaction.RollbackException;
import jakarta.transaction.SystemException;
import jakarta.transaction.Transaction;
import jakarta.transaction.TransactionManager;
import jakarta.transaction.Status;
import org.jboss.tm.listener.TransactionTypeNotSupported;
import com.arjuna.ats.jbossatx.logging.jbossatxLogger;
import com.arjuna.ats.jta.common.JTAEnvironmentBean;
import com.arjuna.ats.jta.common.jtaPropertyManager;
import org.jboss.tm.TransactionLocal;
import org.jboss.tm.TransactionLocalDelegate;
import org.jboss.tm.TransactionTimeoutConfiguration;
import org.jboss.tm.listener.TransactionEvent;
import org.jboss.tm.listener.TransactionListener;
import org.jboss.tm.listener.TransactionListenerRegistry;
import org.jboss.tm.listener.EventType;
import java.util.EnumSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Delegate for JBoss TransactionManager/TransactionLocalDelegate.
* @author kevin
*/
@Deprecated // org.jboss.tm.TransactionLocalDelegate, is Deprecated
public abstract class BaseTransactionManagerDelegate implements TransactionManager, TransactionLocalDelegate, TransactionTimeoutConfiguration, TransactionListenerRegistry
{
private static final String LISTENER_MAP_KEY = "__TX_LISTENERS";
/**
* Delegate transaction manager.
*/
private final TransactionManager transactionManager ;
/**
* Construct the delegate using the specified transaction manager.
* @param transactionManager The delegate transaction manager.
*/
protected BaseTransactionManagerDelegate(final TransactionManager transactionManager)
{
this.transactionManager = transactionManager ;
}
/**
* Begin a transaction and associate it with the current thread.
*/
public void begin()
throws NotSupportedException, SystemException
{
transactionManager.begin() ;
}
/**
* Commit the current transaction and disassociate from the thread.
*/
public void commit()
throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
SecurityException, IllegalStateException, SystemException
{
notifyAssociationListeners(getTransaction(), EventType.DISASSOCIATING);
transactionManager.commit() ;
}
/**
* Get the transaction status.
* @return the transaction status.
*/
public int getStatus()
throws SystemException
{
return transactionManager.getStatus() ;
}
/**
* Get the transaction associated with the thread.
* @return the transaction or null if none associated.
*/
public Transaction getTransaction()
throws SystemException
{
return transactionManager.getTransaction() ;
}
/**
* Resume the specified transaction.
* @param transaction The transaction to resume.
*/
public void resume(final Transaction transaction)
throws InvalidTransactionException, IllegalStateException, SystemException
{
if (transaction == null) {
suspend(); // This is what AtomicAction does
} else {
transactionManager.resume(transaction) ;
notifyAssociationListeners(transaction, EventType.ASSOCIATED);
}
}
/**
* Rollback the current transaction and disassociate from the thread.
*/
public void rollback()
throws IllegalStateException, SecurityException, SystemException
{
notifyAssociationListeners(getTransaction(), EventType.DISASSOCIATING);
transactionManager.rollback() ;
}
/**
* Set rollback only on the current transaction.
*/
public void setRollbackOnly()
throws IllegalStateException, SystemException
{
transactionManager.setRollbackOnly() ;
}
/**
* Set the transaction timeout on the current thread.
* @param timeout The transaction timeout.
*/
public void setTransactionTimeout(final int timeout)
throws SystemException
{
transactionManager.setTransactionTimeout(timeout) ;
}
/**
* register a listener for transaction related events that effect the current thread
* @param listener the callback for event notifications
*/
@Override
public void addListener (Transaction transaction, TransactionListener listener, EnumSet types) throws TransactionTypeNotSupported
{
if (transaction == null)
throw new NullPointerException(); // we could interpret this as meaning register for all transactions
if (!(transaction instanceof com.arjuna.ats.jta.transaction.Transaction))
throw new TransactionTypeNotSupported(jbossatxLogger.i18NLogger.get_unsupported_transaction_type(transaction.getClass()));
Collection listeners = getListeners(transaction, true);
if (listeners != null) {
listeners.add(listener);
// if transaction is already associated with the current thread notify this listener
try {
if (transaction.equals(getTransaction()) && types.contains(EventType.ASSOCIATED))
listener.onEvent(new TransactionEvent(transaction, EnumSet.of(EventType.ASSOCIATED)));
} catch (SystemException e) {
// no transaction associated so do not trigger the ASSOCIATED callback
}
}
}
/**
* Suspend the current transaction.
* @return The suspended transaction.
*/
public Transaction suspend()
throws SystemException
{
if (getStatus() != Status.STATUS_NO_TRANSACTION)
notifyAssociationListeners(getTransaction(), EventType.DISASSOCIATING);
return transactionManager.suspend();
}
// TransactionListener implementation methods.
// return all the event listeners associated with this thread
private Collection getListeners(Transaction transaction, boolean create)
{
if(!jtaPropertyManager.getJTAEnvironmentBean().isTransactionToThreadListenersEnabled()) {
if(create) {
throw new IllegalStateException(jbossatxLogger.i18NLogger.get_transaction_listeners_disabled(
JTAEnvironmentBean.class.getName()+".transactionToThreadListenersEnabled"));
}
return null;
}
com.arjuna.ats.jta.transaction.Transaction txn = (com.arjuna.ats.jta.transaction.Transaction) transaction;
Object resource;
// protect against two concurrent listener registrations both trying to create the initial resource entry
synchronized (transaction) {
resource = txn.getTxLocalResource(LISTENER_MAP_KEY);
if (resource == null && create) {
Collection listeners = new ConcurrentLinkedQueue<>();
txn.putTxLocalResource(LISTENER_MAP_KEY, listeners);
return listeners;
}
}
if (resource != null && !(resource instanceof ConcurrentLinkedQueue)) {
// another container subsystem has inadvertently used our key
throw new IllegalStateException(jbossatxLogger.i18NLogger.get_invalid_transaction_local_resource(resource, LISTENER_MAP_KEY));
}
return (Collection) resource;
}
// notify any listeners for this transaction that there has been an event
private void notifyAssociationListeners(Transaction transaction, EventType reason)
{
if (transaction != null) {
Collection listeners = getListeners(transaction, false);
if (listeners != null && !listeners.isEmpty()) {
TransactionEvent event = new TransactionEvent(transaction, EnumSet.of(reason));
for (TransactionListener s : listeners)
s.onEvent(event);
}
}
}
/////////////////////////
// TransactionLocalDelegate implementation methods. This part is basically
// stateless, we just delegate down to the object storage on the TransactionImple
// Note this has some interesting effects around Transaction termination. The TransactionImple instance
// lifetime is up to tx termination only. After that getTransaction() on the tm returns a new instance
// representing the same tx. Hence TransactionLocal state goes away magically at tx termination time
// since it's part of the TransactionImple instance. That's what we want and saves writing cleanup code.
// On the down side, since locks use the same storage they go away too. This causes us to have to
// jump through some hoops to deal with locks vanishing and maybe never getting unlocked, see below.
/**
* Does the specified transaction contain a value for the transaction local.
*
* @param transactionLocal The associated transaction local.
* @param transaction The associated transaction.
* @return true if a value exists within the specified transaction, false otherwise.
*/
public boolean containsValue(final TransactionLocal transactionLocal, final Transaction transaction) {
com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
if(transactionImple.isAlive()) {
return (transactionImple.getTxLocalResource(transactionLocal) != null ? true : false);
} else {
return false;
}
}
/**
* Get value of the transaction local in the specified transaction.
*
* @param transactionLocal The associated transaction local.
* @param transaction The associated transaction.
* @return The value of the transaction local.
*/
public Object getValue(final TransactionLocal transactionLocal, final Transaction transaction) {
com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
if(transactionImple.isAlive()) {
return transactionImple.getTxLocalResource(transactionLocal);
} else {
return null;
}
}
/**
* Store the value of the transaction local in the specified transaction.
*
* @param transactionLocal The associated transaction local.
* @param transaction The associated transaction.
* @param value The value of the transaction local.
*/
public void storeValue(final TransactionLocal transactionLocal, final Transaction transaction,
final Object value) {
com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
if(transactionImple.isAlive()) {
transactionImple.putTxLocalResource(transactionLocal, value);
} else {
throw new IllegalStateException(jbossatxLogger.i18NLogger.get_cannot_store_transactionlocal(transactionImple));
}
}
/**
* Lock the transaction local in the context of this transaction.
*
* @throws IllegalStateException if the transaction is not active
* @throws InterruptedException if the thread is interrupted
*/
public void lock(final TransactionLocal local, final Transaction transaction)
throws InterruptedException {
com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
if(transactionImple.isAlive()) {
// There is a race here, as the transaction may terminate between the check
// and the lock attempt. See lock() implementation below.
// It's still possible to lock a dead transaction, but that does no real harm.
TransactionLocalLock lock = findLock(local, transaction);
if(lock.lock(transactionImple)) {
return;
}
}
throw new IllegalStateException(jbossatxLogger.i18NLogger.get_cannot_lock_transactionlocal(transactionImple));
}
/**
* Unlock the transaction local in the context of this transaction
*/
public void unlock(final TransactionLocal local, final Transaction transaction) {
TransactionLocalLock lock = findLock(local, transaction);
lock.unlock();
}
// Lock implementation: This used to use a Synchronization for lock storage, but
// we need to be able to lock things in some states where registration of
// Synchronizations is not permitted. Besides, the JTA 1.1 work gives us a nice
// general object storage mechanism on a TransactionImple, so we use that.
// This is the key under which the map of TransactionLocals to locks is stored.
// Bad things will probably happen if users ever use this key themselves
private final String LOCKS_MAP = "__LOCKS_MAP";
// Using string LOCKS_MAP directly as object of synchronization is not recommended
// String literals are centrally interned and could also be locked on by a library,
// potentially having deadlocks or lock collisions
private static final Object locksMapLock = new Object();
// locate and return the lock for a given TransactionLocal+Transaction tuple.
// create it if it does not exist.
private TransactionLocalLock findLock(final TransactionLocal local, final Transaction transaction) {
com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
Map locks; //
// ideally for performance we should sync on the tx instance itself but that may have nasty
// side effects so we use something else as the lock object for the sync block
locks = (Map) transactionImple.getTxLocalResource(LOCKS_MAP);
// this is not a double-check locking anti-pattern, because locks
// is a local variable and thus can not leak.
if (locks == null) {
synchronized (locksMapLock) {
// ensure there is a holder for lock storage on the given tx instance.
locks = (Map) transactionImple.getTxLocalResource(LOCKS_MAP);
if (locks == null) {
locks = new HashMap(); //
transactionImple.putTxLocalResource(LOCKS_MAP, locks);
}
}
}
TransactionLocalLock transactionLocalLock = (TransactionLocalLock) locks.get(local);
if (transactionLocalLock == null) {
synchronized (locks) {
// ensure there is a lock for the specified local+tx tuple
transactionLocalLock = (TransactionLocalLock)locks.get(local);
if (transactionLocalLock == null) {
transactionLocalLock = new TransactionLocalLock();
locks.put(local, transactionLocalLock);
}
}
}
return transactionLocalLock;
}
// A class for the storage of individual lock state:
private class TransactionLocalLock
{
/**
* The locking thread.
*/
private Thread lockingThread ;
/**
* The lock count.
*/
private int lockCount ;
/**
* The lock.
*/
private byte[] lock = new byte[0] ;
/**
* Lock the transaction local within the current thread context.
* true on lock acquired, false otherwise
*/
public boolean lock(com.arjuna.ats.jta.transaction.Transaction tx)
{
// The current code in the app server locks the transaction for all, we follow that practice
synchronized(lock)
{
final Thread currentThread = Thread.currentThread() ;
if (currentThread == lockingThread)
{
lockCount++ ;
return true;
}
while (lockingThread != null)
{
try
{
// lock object instances get thrown away at Transaction termination. That makes it impossible
// to call unlock() on them. Searching through them and unlocking them from the transaction
// termination code is a pain and finalizers suck.
// Hence we need to make sure we don't wait forever for a notify
// that will never come. Probably the only thing that will terminate a Transaction in another
// Thread is the transaction reaper, so we wait not longer than the tx timeout plus a fudge factor.
long timeout = 0;
try {
timeout = getTransactionTimeout();
} catch(SystemException e) {}
lock.wait(timeout+1000);
if(!tx.isAlive()) {
// transaction is dead, can't be locked, cleanup
lockingThread = null;
lockCount = 0;
return false;
}
}
catch (final InterruptedException ie) {}
}
lockingThread = currentThread ;
lockCount ++ ;
return true;
}
}
/**
* Unlock the transaction local within the current thread context.
*/
public void unlock()
{
synchronized(lock)
{
if(lockCount == 0 && lockingThread == null) {
// the lock was probably reset by a transaction termination.
// we fail silent to save the caller having to deal with race condition.
return;
}
final Thread currentThread = Thread.currentThread() ;
if (currentThread != lockingThread)
{
throw new IllegalStateException(
jbossatxLogger.i18NLogger.get_cannot_store_transactionlocal(lockingThread, currentThread)) ;
}
if (--lockCount == 0)
{
lockingThread = null ;
lock.notify() ;
}
}
}
}
}