FileDocCategorySizeDatePackage
AbstractTransactionController.javaAPI DocGlassfish v2 API22420Tue May 22 16:54:54 BST 2007oracle.toplink.essentials.transaction

AbstractTransactionController

public abstract class AbstractTransactionController extends Object implements ExternalTransactionController

Purpose: Abstract implementation of an ExternalTransactionController.

Description: This class implements the ExternalTransactionController interface. Concrete implementations of this class are responsible for performing the coordination with the external transaction manager through whatever means available to that manager. Different transaction services may do this in slightly different ways, but most common ones (JTA and JTS/OTS) will use a synchronization interface.

see
AbstractSynchronizationListener
see
oracle.toplink.essentials.sessions.ExternalTransactionController

Fields Summary
protected Hashtable
unitsOfWork
Table of external transaction object keys and unit of work values
protected AbstractSession
session
The session this controller is responsible for controlling
protected SynchronizationListenerFactory
listenerFactory
Generates listener instances for synchronization
protected ThreadLocal
activeUnitOfWorkThreadLocal
PERF: Cache the active uow in a thread local.
Constructors Summary
public AbstractTransactionController()
INTERNAL: Return a new controller.

        this.unitsOfWork = new Hashtable();
        this.activeUnitOfWorkThreadLocal = new ThreadLocal();
    
Methods Summary
public voidaddUnitOfWork(java.lang.Object transaction, oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl activeUnitOfWork)
INTERNAL: Add a UnitOfWork object to the Hashtable keyed on the external transaction object.

        this.activeUnitOfWorkThreadLocal.set(null);
        getUnitsOfWork().put(transaction, activeUnitOfWork);
    
public voidbeginTransaction(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Begin an external transaction.

param
session The session for which the transaction is being begun.

        try {
            Object status = getTransactionStatus();
            logTxStateTrace(session, "TX_begin", status);

            // Make sure that we are in a state that we can actually start 
            // a transaction (e.g. ensure one is not already in progress)
            if (canBeginTransaction_impl(status)) {
                logTxTrace(session, "TX_beginningTxn", null);
                beginTransaction_impl();
                session.setWasJTSTransactionInternallyStarted(true);
            }
        } catch (Exception exception) {
            throw TransactionException.errorBeginningExternalTransaction(exception);
        }
    
protected abstract voidbeginTransaction_impl()
INTERNAL: Begin an external transaction. Do this in a way appropriate to the transaction subsystem.

public voidbindToCurrentTransaction(oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl unitOfWork, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Associate the given unit of work and TopLink session with the active external transaction. This may be done by whatever means supported by the transaction manager (i.e. through a synchronization protocol).

param
unitOfWork The unit of work that is to be bound to the active transaction
param
session The session ancestor of the unit of work

        Object status = getTransactionStatus();
        logTxStateTrace(unitOfWork, "TX_bind", status);
        try {
            Object txn = getTransaction();
            if (txn == null) {
                // If no external transaction is active then start one through the uow
                unitOfWork.beginTransaction();
                txn = getTransaction();
            }

            // If there still is no active txn then something is wrong
            if (txn == null) {
                throw TransactionException.externalTransactionNotActive();
            }

            // Create and register the synchronization listener
            AbstractSynchronizationListener listener = getListenerFactory().newSynchronizationListener(unitOfWork, session, txn, this);

            registerSynchronization_impl(listener, txn);
            unitOfWork.setSynchronized(true);

        } catch (Exception exception) {
            throw TransactionException.errorBindingToExternalTransaction(exception);
        }
    
protected abstract booleancanBeginTransaction_impl(java.lang.Object status)
INTERNAL: Return true if the status indicates that a transaction can be started. This would normally mean that no transaction is currently active. The status is interpreted by the transaction subsystem.

param
status The current transaction status
return
true if the current state allows for a transaction to be started

protected abstract booleancanCommitTransaction_impl(java.lang.Object status)
INTERNAL: Return true if the status indicates that a transaction can be committed. This would normally mean that a transaction is currently active. The status is interpreted by the transaction subsystem.

param
status The current transaction status
return
true if the current state allows for a transaction to be committed

protected abstract booleancanIssueSQLToDatabase_impl(java.lang.Object status)
INTERNAL: Return true if the status indicates that the SQL should be issued to the db. This would normally mean that a transaction was active and not being rolled back or marked for rollback. The status is interpreted by the transaction subsystem.

param
status The current transaction status
return
true if the current state allows for the SQL to be sent to the database

protected abstract booleancanMergeUnitOfWork_impl(java.lang.Object status)
INTERNAL: Return true if the status indicates that the unit of work should be merged into the shared cache. This would normally mean that the transaction was committed successfully. The status is interpreted by the transaction subsystem.

param
status The current transaction status
return
true if the current state dictates that the unit of work should be merged

protected abstract booleancanRollbackTransaction_impl(java.lang.Object status)
INTERNAL: Return true if the status indicates that a transaction can be rolled back. This would normally mean that a transaction is currently active. The status is interpreted by the transaction subsystem.

param
status The current transaction status
return
true if the current state allows for a transaction to be rolled back

public voidcommitTransaction(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Commit the external transaction.

param
session The session for which the transaction is being committed.

        try {
            Object status = getTransactionStatus();
            logTxStateTrace(session, "TX_commit", status);

            if (canCommitTransaction_impl(status)) {
                logTxTrace(session, "TX_committingTxn", null);

                session.setWasJTSTransactionInternallyStarted(false);
                commitTransaction_impl();
            }
        } catch (Exception exception) {
            throw TransactionException.errorCommittingExternalTransaction(exception);
        }
    
protected abstract voidcommitTransaction_impl()
INTERNAL: Commit the external transaction. Do this in a way appropriate to the transaction subsystem.

public oracle.toplink.essentials.internal.sessions.UnitOfWorkImplgetActiveUnitOfWork()
INTERNAL: Return the active unit of work for the current external transaction. If no transaction is active then return null. If a transaction is active but no unit of work has been bound to it then create and return one.

        Object transaction = getTransaction();
        if (transaction == null) {
            return null;
        }
        
        UnitOfWorkImpl activeUnitOfWork = lookupActiveUnitOfWork(transaction);
        if (activeUnitOfWork == null) {
            // Txn is active but no UoW has been associated with it yet, so create one.
            activeUnitOfWork = (UnitOfWorkImpl) getSession().acquireUnitOfWork();
            Object transactionKey = getTransactionKey(transaction);
            addUnitOfWork(transactionKey, activeUnitOfWork);
            activeUnitOfWork.setTransaction(transaction);
            this.activeUnitOfWorkThreadLocal.set(activeUnitOfWork);
        }
        return activeUnitOfWork;
    
public oracle.toplink.essentials.transaction.SynchronizationListenerFactorygetListenerFactory()
INTERNAL: Get the factory used to generate synchronization listeners.

        return listenerFactory;
    
public oracle.toplink.essentials.internal.sessions.AbstractSessiongetSession()
INTERNAL: Return the manager's session.

        return session;
    
public java.lang.ObjectgetTransaction()
INTERNAL: Return the active external transaction object, or null if none is active. This may be in whatever form the transaction system uses.

        try {
            return getTransaction_impl();
        } catch (Exception exception) {
            throw TransactionException.errorGettingExternalTransaction(exception);
        }
    
public java.lang.ObjectgetTransactionKey(java.lang.Object transaction)
INTERNAL: Return a key for the specified external transaction object. The key is just something that can be inserted into a hashtable (must support hashCode() and equals() methods).

        try {
            return getTransactionKey_impl(transaction);
        } catch (Exception exception) {
            throw TransactionException.errorGettingExternalTransaction(exception);
        }
    
protected abstract java.lang.ObjectgetTransactionKey_impl(java.lang.Object transaction)
INTERNAL: Return a key for the specified external transaction object. The key is just something that can be inserted into a hashtable (must support hashCode() and equals() methods).

param
transaction The transaction to which the returned key applies (may be null)
return
A key for the passed in transaction, or null if no transaction specified

public java.lang.ObjectgetTransactionStatus()
INTERNAL: Return the transaction status. This may be any type of status or value, depending upon the transaction system.

        try {
            return getTransactionStatus_impl();
        } catch (Exception exception) {
            throw TransactionException.errorGettingExternalTransactionStatus(exception);
        }
    
protected abstract java.lang.ObjectgetTransactionStatus_impl()
INTERNAL: Return the transaction status. This may be any type of status or value, depending upon the transaction system.

return
The current transaction status

protected abstract java.lang.ObjectgetTransaction_impl()
INTERNAL: Return the active external transaction for the calling thread, or null if none is currently active for this thread.

return
The active transaction object, or null if no transaction is active

public java.util.HashtablegetUnitsOfWork()
INTERNAL: Return the hashtable keyed on the external transaction objectss with values that are the associated units of work.

        return unitsOfWork;
    
public booleanhasActiveUnitOfWork()
INTERNAL: Return true if there is a unit of work associated with the active external transaction. Return false if no transaction is current, or if no uow has been associated with the active transaction yet.

        return this.lookupActiveUnitOfWork() != null;
    
public abstract booleanisRolledBack_impl(java.lang.Object status)
INTERNAL: Return true if the transaction is in the roleld back state.

public java.lang.ObjectjndiLookup(java.lang.String jndiName)
PUBLIC: Look up a given name in JNDI. This can be used by a subclass or even an application to look up transaction artifacts that are required for the implementation.

The lookup assumes that it is taking place on the server side, and that the InitialContext can be used without requiring any special properties.

param
jndiName The name to look up
return
The object bound in JNDI to the specified name
exception
TransactionException Thrown in case of lookup failure

        Context context = null;
        Object jndiObject = null;
        try {
            context = new InitialContext();
            jndiObject = context.lookup(jndiName);
        } catch (NamingException ex) {
            throw TransactionException.jndiLookupException(jndiName, ex);
        } finally {
            try {
                context.close();
            } catch (Exception ex2) {/* ignore */
            }
        }
        return jndiObject;
    
public voidlogTxStateTrace(oracle.toplink.essentials.internal.sessions.AbstractSession session, java.lang.String msgInd, java.lang.Object status)

        if (session.shouldLog(SessionLog.FINER, SessionLog.TRANSACTION)) {
            String statusString = statusToString_impl(status);
            Object[] args = { statusString };
            session.log(SessionLog.FINER, SessionLog.TRANSACTION, msgInd, args);
        }
    
public voidlogTxTrace(oracle.toplink.essentials.internal.sessions.AbstractSession session, java.lang.String msgInd, java.lang.Object[] args)

        session.log(SessionLog.FINER, SessionLog.TRANSACTION, msgInd, args);
    
public oracle.toplink.essentials.internal.sessions.UnitOfWorkImpllookupActiveUnitOfWork()
INTERNAL: Return the unit of work associated with the active external transaction. Return null if no transaction is active, or if no uow has been associated with the active transaction yet.

        return lookupActiveUnitOfWork(getTransaction());
    
public oracle.toplink.essentials.internal.sessions.UnitOfWorkImpllookupActiveUnitOfWork(java.lang.Object transaction)
INTERNAL: Return the unit of work associated with the active external transaction. Return null if no transaction is active, or if no uow has been associated with the active transaction yet.

        if (transaction == null) {
            return null;
        }
        Object transactionKey = getTransactionKey(transaction);

        // PERF: Cache the active unit of work in a thread local.
        // This is just a heuristic, so uses == and no tx-key and direct access as extreamly high throughput.
        UnitOfWorkImpl activeUnitOfWork = (UnitOfWorkImpl)this.activeUnitOfWorkThreadLocal.get();
        if (activeUnitOfWork != null) {
            if (transaction == activeUnitOfWork.getTransaction()) {
                return activeUnitOfWork;
            }
        }
        activeUnitOfWork = (UnitOfWorkImpl)getUnitsOfWork().get(transactionKey);
        if (activeUnitOfWork != null) {
            activeUnitOfWork.setTransaction(transaction);
        }
        this.activeUnitOfWorkThreadLocal.set(activeUnitOfWork);
        return activeUnitOfWork;
    
public voidmarkTransactionForRollback()
INTERNAL: Mark the external transaction for rollback.

        try {
            markTransactionForRollback_impl();
        } catch (Exception exception) {
            throw TransactionException.errorMarkingTransactionForRollback(exception);
        }
    
protected abstract voidmarkTransactionForRollback_impl()
INTERNAL: Mark the external transaction for rollback. Do this in a way appropriate to the transaction subsystem.

public booleannoTransactionOrRolledBackOrCommited()
INTERNAL: Used the EJB 3.0 to determine if a transaction is in a state where an EntityManager can be closed

        try {
            Object status = getTransactionStatus();
            return canBeginTransaction_impl(status) || canMergeUnitOfWork_impl(status) || isRolledBack_impl(status);
        } catch (Exception exception) {
            throw TransactionException.errorGettingExternalTransactionStatus(exception);
        }
    
public voidregisterSynchronizationListener(oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl uow, oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Associate the given unit of work and TopLink session with the current external transaction. This method is offered only for backwards compatibility.

        this.bindToCurrentTransaction(uow, session);
    
protected abstract voidregisterSynchronization_impl(oracle.toplink.essentials.transaction.AbstractSynchronizationListener listener, java.lang.Object txn)
INTERNAL: Register the specified synchronization listener with the given active transaction.

param
listener The synchronization listener created for this transaction
param
txn The active transaction for which notification is being requested

public voidremoveUnitOfWork(java.lang.Object transaction)
INTERNAL: Remove the unit of work associated with the transaction passed in.

        if (transaction != null) {
            getUnitsOfWork().remove(transaction);
        }
        this.activeUnitOfWorkThreadLocal.set(null);
    
public voidrollbackTransaction(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Roll back the external transaction.

param
session The session for which the transaction is being rolled back.

        try {
            Object status = getTransactionStatus();
            logTxStateTrace(session, "TX_rollback", status);

            session.setWasJTSTransactionInternallyStarted(false);

            // Only roll back if there is a transaction to roll back
            if ((canRollbackTransaction_impl(status)) && (getTransaction() != null)) {
                logTxTrace(session, "TX_rollingBackTxn", null);
                rollbackTransaction_impl();
            }
        } catch (Exception exception) {
            throw TransactionException.errorRollingBackExternalTransaction(exception);
        }
    
protected abstract voidrollbackTransaction_impl()
INTERNAL: Roll back the external transaction. Do this in a way appropriate to the transaction subsystem.

public voidsetListenerFactory(oracle.toplink.essentials.transaction.SynchronizationListenerFactory factory)
INTERNAL: Set the factory used to generate synchronization listeners. This should be set if a listener other than the default one is being used.

        listenerFactory = factory;
    
public voidsetSession(oracle.toplink.essentials.internal.sessions.AbstractSession session)
INTERNAL: Set the manager's session.

        this.session = session;
    
protected voidsetUnitsOfWork(java.util.Hashtable unitsOfWork)
INTERNAL: Set the table of transactions to units of work.

        this.unitsOfWork = unitsOfWork;
    
protected abstract java.lang.StringstatusToString_impl(java.lang.Object status)
INTERNAL: Convert the status to a string for tracing.