FileDocCategorySizeDatePackage
J2EETransaction.javaAPI DocGlassfish v2 API23688Fri May 04 22:34:52 BST 2007com.sun.enterprise.distributedtx

J2EETransaction

public final class J2EETransaction extends TimerTask implements Transaction
This class implements the JTA Transaction API for the J2EE RI. It is a wrapper over the JTS Transaction object that provides optimized local transaction support when a transaction uses zero/one non-XA resource, and delegates to JTS otherwise. This object can be in two states: local tx (jtsTx==null) or global (JTS) tx. If jtsTx!=null, all calls are delegated to jtsTx. Time out capability is added to the local transactions. This class extends the TimerTask. When the transaction needs to be timedout, this schedules with the timer. At the commit and rollback time, task will be cancelled. If the transaction is timedout, run() method will be called and transaction will be marked for rollback.

Fields Summary
static Logger
_logger
private static com.sun.enterprise.util.i18n.StringManager
sm
private static long
txIdCounter
private long
txId
private J2EEXid
xid
static J2EETransactionManagerOpt
j2eeTM
private Transaction
jtsTx
private ResourceHandle
nonXAResource
private ResourceHandle
laoResource
private int
localTxStatus
private Vector
syncs
private Vector
interposedSyncs
private boolean
commitStarted
private long
startTime
private boolean
isTimedOut
private boolean
isTimerTask
private int
timeout
private boolean
imported
private HashMap
resourceTable
private HashMap
userResourceMap
private Object
activeTxCache
private Map
txEntityManagerMap
private Map
extendedEntityManagerMap
private String
componentName
private ArrayList
resourceNames
private Object
containerData
private static boolean
isTimerInitialized
private static Timer
timer
private static final byte[]
bqual
Constructors Summary
J2EETransaction()

        this.txId = getNewTxId();
        this.xid = new J2EEXid(txId);
        this.resourceTable = new HashMap();
        localTxStatus = Status.STATUS_ACTIVE;
        startTime=System.currentTimeMillis();
        if (_logger.isLoggable(Level.FINE)) {
	        _logger.log(Level.FINE,"--Created new J2EETransaction, txId = "+txId);
        }
    
J2EETransaction(int timeout)

        this();
        if (!isTimerInitialized)
            initializeTimer();
        timer.schedule(this,timeout * 1000);
        isTimerTask = true;
        this.timeout = timeout;
    
J2EETransaction(Transaction jtsTx)

	this();
	this.jtsTx = jtsTx;
    
Methods Summary
public voidaddExtendedEntityManagerMapping(javax.persistence.EntityManagerFactory emf, javax.persistence.EntityManager em)

        getExtendedEntityManagerMap().put(emf, em);
    
synchronized voidaddResourceName(java.lang.String resourceName)

        if (resourceNames == null)
            resourceNames = new ArrayList<String>();
        resourceNames.add(resourceName);
    
public voidaddTxEntityManagerMapping(javax.persistence.EntityManagerFactory emf, javax.persistence.EntityManager em)

        getTxEntityManagerMap().put(emf, em);
    
intcancelTimerTask()

        cancel();
        return timeout;
    
public voidcommit()

	// START local transaction timeout
	// If this transaction is set for timeout, cancel it as it is in the commit state
	if (isTimerTask)
		cancel();
	// END local transaction timeout
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE,"--In J2EETransaction.commit, jtsTx="+jtsTx
			    +" nonXAResource="+ nonXAResource);
        }
	commitStarted = true;

	if ( jtsTx != null ) {
	    try {
		jtsTx.commit();
	    } finally {
		j2eeTM.clearThreadTx();
                onTxCompletion(true);
	    }
	}
	else { // local tx
	    try {
		if ( isTimedOut ) {
		    // rollback nonXA resource
		    if ( nonXAResource != null )
			nonXAResource.getXAResource().rollback(xid);
		    localTxStatus = Status.STATUS_ROLLEDBACK;
		    throw new RollbackException(sm.getString("enterprise_distributedtx.rollback_timeout"));
		}
		if ( isRollbackOnly() ) {
		    // rollback nonXA resource
		    if ( nonXAResource != null )
			nonXAResource.getXAResource().rollback(xid);
		    localTxStatus = Status.STATUS_ROLLEDBACK;
		    throw new RollbackException(sm.getString("enterprise_distributedtx.mark_rollback"));
		}
		// call beforeCompletion
		for ( int i=0; i<syncs.size(); i++ ) {
		    try {
			Synchronization sync = (Synchronization)syncs.elementAt(i);
			sync.beforeCompletion();
		    } catch ( RuntimeException ex ) { 
                        setRollbackOnly();
                    } catch (Exception ex) { } 
		}
		for ( int i=0; i<interposedSyncs.size(); i++ ) {
		    try {
			Synchronization sync = (Synchronization)interposedSyncs.elementAt(i);
			sync.beforeCompletion();
		    } catch ( RuntimeException ex ) {
                        setRollbackOnly();  
                    } catch (Exception ex) { }
                }
		// check rollbackonly again, in case any of the beforeCompletion
		// calls marked it for rollback.
		if ( isRollbackOnly()) {
            //Check if it is a Local Transaction
            if(jtsTx == null) {
		        if ( nonXAResource != null )
			    nonXAResource.getXAResource().rollback(xid);
		        localTxStatus = Status.STATUS_ROLLEDBACK;
		        throw new RollbackException(sm.getString("enterprise_distributedtx.mark_rollback"));
            // else it is a global transaction
            } else {
                jtsTx.rollback();
                localTxStatus = Status.STATUS_ROLLEDBACK;
                throw new RollbackException(sm.getString("enterprise_distributedtx.mark_rollback"));
            }
		}
		// check if there is a jtsTx active, in case any of the
		// beforeCompletions registered the first XA resource.
		if ( jtsTx != null ) {
		    jtsTx.commit();
			//IASRI START 4731186
			localTxStatus = Status.STATUS_COMMITTED;
			//IASRI END 4731186
		    // Note: JTS will not call afterCompletions in this case,
		    // because no syncs have been registered with JTS.
		    // So afterCompletions are called in finally block below.
		}
		else {
		    // do single-phase commit on nonXA resource
		    if ( nonXAResource != null )
			nonXAResource.getXAResource().commit(xid, true);

		    // XXX should this be STATUS_NO_TRANSACTION ?
		    localTxStatus = Status.STATUS_COMMITTED;
		}
	    } catch ( RollbackException ex ) {
		localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
		throw ex;
	    } catch ( SystemException ex ) {
		// localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
                localTxStatus = Status.STATUS_COMMITTING;
		throw ex;
	    } catch ( Exception ex ) {
		localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
                SystemException exc = new SystemException();
                exc.initCause(ex);
                throw exc;
	    } finally {
		j2eeTM.clearThreadTx();
		for ( int i=0; i<interposedSyncs.size(); i++ ) {
		    try { 
			Synchronization sync = (Synchronization)interposedSyncs.elementAt(i);
			sync.afterCompletion(localTxStatus);
		    } catch ( Exception ex ) {}
		}
		// call afterCompletions
		for ( int i=0; i<syncs.size(); i++ ) {
		    try {
			Synchronization sync = (Synchronization)syncs.elementAt(i);
			sync.afterCompletion(localTxStatus);
		    } catch ( Exception ex ) {}
		}
                onTxCompletion(true);
	    }
	}
    
public booleandelistResource(javax.transaction.xa.XAResource xaRes, int flag)

	    // START OF IASRI 4660742
      if (_logger.isLoggable(Level.FINE)) {
	        _logger.log(Level.FINE,"--In J2EETransaction.delistResource, jtsTx="
          +jtsTx +" nonXAResource="+nonXAResource);
       }
	    // END OF IASRI 4660742

	if ( jtsTx != null )
	    return jtsTx.delistResource(xaRes, flag);
	else
	    throw new IllegalStateException(sm.getString("enterprise_distributedtx.deleteresource_for_localtx"));
    
public booleanenlistResource(javax.transaction.xa.XAResource xaRes)

      if (_logger.isLoggable(Level.FINE)) {
	        _logger.log(Level.FINE,"--In J2EETransaction.enlistResource, jtsTx="
			    +jtsTx+" nonXAResource="+nonXAResource);
       }
	if ( jtsTx != null )
	    return jtsTx.enlistResource(xaRes);
	else if ( nonXAResource != null )
	    throw new IllegalStateException(sm.getString("enterprise_distributedtx.already_has_nonxa"));
	// IASRI END 4723068
	/***
	else  // XXX what to do ? Start a new JTS tx ?
	    throw new IllegalStateException("J2EETransaction.enlistResource called for local tx");
	***/
	else  { //  Start a new JTS tx
	    j2eeTM.startJTSTx(this);
	    return jtsTx.enlistResource(xaRes);
	}
	// IASRI END 4723068
    
public booleanequals(java.lang.Object other)

	if ( other == this )
	    return true;
	if ( other instanceof J2EETransaction ) {
	    J2EETransaction othertx = (J2EETransaction)other;
	    return ( txId == othertx.txId );
	}
	return false;
    
public java.lang.ObjectgetActiveTxCache()

	return this.activeTxCache;
    
public java.util.SetgetAllParticipatingPools()
Return all pools registered in the resourceTable. This will cut down the scope of pools on which transactionComplted is called by the PoolManagerImpl. This method will return only those pools that have ever participated in a tx

        return (Set) resourceTable.keySet();
    
java.lang.StringgetComponentName()

        return componentName;
    
public java.lang.ObjectgetContainerData()

        return containerData;
    
public javax.persistence.EntityManagergetExtendedEntityManager(javax.persistence.EntityManagerFactory emf)

        return getExtendedEntityManagerMap().get(emf);
    
private java.util.MapgetExtendedEntityManagerMap()

        if( extendedEntityManagerMap == null ) {
            extendedEntityManagerMap = 
                new HashMap<EntityManagerFactory, EntityManager>();
        }
        return extendedEntityManagerMap;
    
javax.transaction.TransactiongetJTSTx()

	return jtsTx;
    
ResourceHandlegetLAOResource()

        return laoResource;
    
javax.transaction.xa.XidgetLocalXid()

	return xid;
    
private static synchronized longgetNewTxId()

	long newTxId = txIdCounter++;
	return newTxId;
    
public ResourceHandlegetNonXAResource()

	return nonXAResource;
    
public intgetRemainingTimeout()
Return duration in seconds before transaction would timeout. Returns zero if this transaction has no timeout set. Returns negative value if already timed out.

        if (timeout == 0) {
            return timeout;
        } else if (isTimedOut) {
            return -1;
        } else {
            // compute how much time left before transaction times out
            return timeout - (int)((System.currentTimeMillis() - startTime) / 1000L);
        }
    
synchronized java.util.ArrayListgetResourceNames()

        return resourceNames;
    
public java.util.SetgetResources(java.lang.String poolName)

        return (Set) resourceTable.get(poolName);
    
public longgetStartTime()

        return startTime;
    
public intgetStatus()

	if ( jtsTx != null )
	    return jtsTx.getStatus();
	else
	    return localTxStatus;
    
public java.lang.StringgetTransactionId()

        return xid.toString();
    
public javax.persistence.EntityManagergetTxEntityManager(javax.persistence.EntityManagerFactory emf)

        return getTxEntityManagerMap().get(emf);
    
private java.util.MapgetTxEntityManagerMap()

        if( txEntityManagerMap == null ) {
            txEntityManagerMap = 
                new HashMap<EntityManagerFactory, EntityManager>();
        }
        return txEntityManagerMap;
    
synchronized java.lang.ObjectgetUserResource(java.lang.Object key)

        if (userResourceMap == null)
            return null;
        return userResourceMap.get(key);
    
public inthashCode()

	return (int)txId;
    
private static synchronized voidinitializeTimer()


         
        if (isTimerInitialized)
            return;
        timer = new Timer(true); // daemon 
        isTimerInitialized = true;
    
booleanisAssociatedTimeout()

        return isTimerTask;
    
booleanisImportedTransaction()

        return imported;
    
booleanisLocalTx()

	return (jtsTx==null);
    
private booleanisRollbackOnly()

	int status;
	if ( jtsTx != null )
	    status = jtsTx.getStatus();
	else
	    status = localTxStatus;

	return (status == Status.STATUS_MARKED_ROLLBACK);
    
booleanisTimedout()

        return isTimedOut;
    
private voidonTxCompletion(boolean status)

        for (Map.Entry<EntityManagerFactory, EntityManager> entry : 
            getTxEntityManagerMap().entrySet()) {
            
            EntityManager em = entry.getValue();
            if (em.isOpen()) {
                try {
                    em.close();
                } catch (Throwable th) {
                    if (_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE, "Exception while closing em.", th);
                    } 
                }
            }
        }
    
synchronized voidputUserResource(java.lang.Object key, java.lang.Object value)

        if (userResourceMap == null)
            userResourceMap = new HashMap<Object, Object>();
        userResourceMap.put(key, value);
    
voidregisterInterposedSynchronization(javax.transaction.Synchronization sync)

        interposedSyncs.add(sync);
    
public voidregisterSynchronization(javax.transaction.Synchronization sync)

	    // START OF IASRI 4660742
      if (_logger.isLoggable(Level.FINE)) {
	        _logger.log(Level.FINE,"--In J2EETransaction.registerSynchronization, jtsTx=" +jtsTx+" nonXAResource="+nonXAResource);
      }
	    // END OF IASRI 4660742

	if ( jtsTx != null )
	    jtsTx.registerSynchronization(sync);
	else
	    syncs.add(sync);
    
public voidremoveExtendedEntityManagerMapping(javax.persistence.EntityManagerFactory emf)

        getExtendedEntityManagerMap().remove(emf);
    
public voidrollback()

        // START local transaction timeout
        // If this transaction is set for timeout, cancel it as it is in the rollback state
        if (isTimerTask)
            cancel();
        // END local transaction timeout
        if (_logger.isLoggable(Level.FINE)) {
	    _logger.log(Level.FINE,"--In J2EETransaction.rollback, jtsTx="+jtsTx
		    +" nonXAResource="+nonXAResource);
        }
	try {
	    if ( jtsTx != null )
		jtsTx.rollback();
	    else { // rollback nonXA resource
		if ( nonXAResource != null )
		    nonXAResource.getXAResource().rollback(xid);

		// XXX should this be STATUS_NO_TRANSACTION ?
		localTxStatus = Status.STATUS_ROLLEDBACK;
	    }
	} catch ( Exception ex ) {
	    localTxStatus = Status.STATUS_ROLLEDBACK; // XXX is this correct ?
	} finally {
	    j2eeTM.clearThreadTx();
	    if ( jtsTx == null ) {
		// call afterCompletions
		for ( int i=0; i<syncs.size(); i++ ) {
		    try {
			Synchronization sync = (Synchronization)syncs.elementAt(i);
			sync.afterCompletion(Status.STATUS_ROLLEDBACK);
		    } catch ( Exception ex ) {}
		}
	    }
            onTxCompletion(false);
	}
    
public voidrun()

        isTimedOut = true;
        try {
	    setRollbackOnly();
	} catch (Exception e) {
	    e.printStackTrace();
	}
    
public voidsetActiveTxCache(java.lang.Object cache)

	this.activeTxCache = cache;
    
voidsetComponentName(java.lang.String componentName)

        this.componentName = componentName;
    
public voidsetContainerData(java.lang.Object data)

        containerData = data;
    
voidsetImportedTransaction()

        imported = true;
    
voidsetJTSTx(javax.transaction.Transaction jtsTx)

	this.jtsTx = jtsTx;

	if ( !commitStarted ) {
	    // register syncs
	    for ( int i=0; i<syncs.size(); i++ )
		jtsTx.registerSynchronization((Synchronization)syncs.elementAt(i));
	    for ( int i=0; i<interposedSyncs.size(); i++ )
		((TransactionImpl)jtsTx).registerInterposedSynchronization((Synchronization)interposedSyncs.elementAt(i));
	}
    
voidsetLAOResource(ResourceHandle h)

        laoResource = h;
    
voidsetNonXAResource(ResourceHandle h)

	nonXAResource = h;
    
public voidsetResources(java.util.Set resources, java.lang.String poolName)

        resourceTable.put(poolName, resources);
    
public voidsetRollbackOnly()

	if ( jtsTx != null )
	    jtsTx.setRollbackOnly();
	else
	    localTxStatus = Status.STATUS_MARKED_ROLLBACK;
    
public java.lang.StringtoString()

	return "J2EETransaction: txId="+txId+" nonXAResource="+nonXAResource
		+" jtsTx="+jtsTx+" localTxStatus="+localTxStatus
		+" syncs="+syncs;