Package com.sun.enterprise.transaction

Source Code of com.sun.enterprise.transaction.JavaEETransactionManagerSimplified

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.enterprise.transaction;

import java.util.*;
import java.util.logging.*;
import java.rmi.RemoteException;

import javax.transaction.*;
import javax.transaction.xa.*;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkException;

import com.sun.appserv.util.cache.Cache;
import com.sun.appserv.util.cache.BaseCache;

import com.sun.enterprise.transaction.api.JavaEETransaction;
import com.sun.enterprise.transaction.api.JavaEETransactionManager;
import com.sun.enterprise.transaction.api.TransactionAdminBean;
import com.sun.enterprise.transaction.api.XAResourceWrapper;
import com.sun.enterprise.transaction.config.TransactionService;
import com.sun.enterprise.transaction.spi.JavaEETransactionManagerDelegate;
import com.sun.enterprise.transaction.spi.TransactionalResource;
import com.sun.enterprise.transaction.spi.TransactionInternal;
import com.sun.enterprise.transaction.monitoring.TransactionServiceProbeProvider;
import com.sun.enterprise.transaction.monitoring.TransactionServiceStatsProvider;

import com.sun.logging.LogDomains;
import com.sun.enterprise.util.i18n.StringManager;

import javax.inject.Inject;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.annotations.ContractsProvided;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.Rank;
import org.glassfish.hk2.api.ServiceLocator;

import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.api.invocation.InvocationException;
import org.glassfish.api.invocation.ResourceHandler;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.common.util.Constants;

import org.glassfish.external.probe.provider.PluginPoint;
import org.glassfish.external.probe.provider.StatsProviderManager;

import com.sun.enterprise.config.serverbeans.ModuleMonitoringLevels;

/**
* Implementation of javax.transaction.TransactionManager interface.
* This class provides non-XA local transaction support and delegates
* to implementation of the JavaEETransactionManagerDelegate for XA
* or LAO optimization, and complete JTS implementation.
*
* @author Tony Ng
* @author Marina Vatkina
*/
@Service
@ContractsProvided({TransactionManager.class, JavaEETransactionManager.class})
@Rank(Constants.DEFAULT_IMPLEMENTATION_RANK) // This should be the default impl if it is available
public class JavaEETransactionManagerSimplified
        implements JavaEETransactionManager, PostConstruct {

    protected Logger _logger = LogDomains.getLogger(JavaEETransactionManagerSimplified.class, LogDomains.JTA_LOGGER);

    @Inject private ServiceLocator habitat;

    @Inject protected InvocationManager invMgr;

    private JavaEETransactionManagerDelegate delegate;

    // Sting Manager for Localization
    private static StringManager sm
           = StringManager.getManager(JavaEETransactionManagerSimplified.class);

    // Note: this is not inheritable because we dont want transactions
    // to be inherited by child threads.
    private ThreadLocal<JavaEETransaction> transactions;

    private ThreadLocal localCallCounter;
    private ThreadLocal<JavaEETransactionManagerDelegate> delegates;

    // If multipleEnlistDelists is set to true, with in the transaction, for the same
    //  - connection multiple enlistments and delistments might happen
    // - By setting the System property ALLOW_MULTIPLE_ENLISTS_DELISTS to true
    // - multipleEnlistDelists can be enabled
    private boolean multipleEnlistDelists = false;

    private int transactionTimeout;
    private ThreadLocal<Integer> txnTmout = new ThreadLocal();

    private int purgeCancelledTtransactions = 0;

    // admin and monitoring related parameters
    private  static final Hashtable statusMap = new Hashtable();
    private List activeTransactions = Collections.synchronizedList(new ArrayList());
    private boolean monitoringEnabled = false;

    private TransactionServiceProbeProvider monitor;
    private Hashtable txnTable = null;

    private Cache resourceTable;

    private  Timer _timer = new Timer("transaction-manager", true);

    static {
        statusMap.put(Status.STATUS_ACTIVE, "Active");
        statusMap.put(Status.STATUS_MARKED_ROLLBACK, "MarkedRollback");
        statusMap.put(Status.STATUS_PREPARED, "Prepared");
        statusMap.put(Status.STATUS_COMMITTED, "Committed");
        statusMap.put(Status.STATUS_ROLLEDBACK, "RolledBack");
        statusMap.put(Status.STATUS_UNKNOWN, "UnKnown");
        statusMap.put(Status.STATUS_NO_TRANSACTION, "NoTransaction");
        statusMap.put(Status.STATUS_PREPARING, "Preparing");
        statusMap.put(Status.STATUS_COMMITTING, "Committing");
        statusMap.put(Status.STATUS_ROLLING_BACK, "RollingBack");

    }
    public JavaEETransactionManagerSimplified() {
        transactions = new ThreadLocal<JavaEETransaction>();
        localCallCounter = new ThreadLocal();
        delegates = new ThreadLocal<JavaEETransactionManagerDelegate>();
    }

    public void postConstruct() {
        initDelegates();
        initProperties();
    }

    private void initProperties() {
        int maxEntries = 8192; // FIXME: this maxEntry should be a config
        float loadFactor = 0.75f; // FIXME: this loadFactor should be a config
        // for now, let's get it from system prop
        try {
            String mEnlistDelists
                = System.getProperty("ALLOW_MULTIPLE_ENLISTS_DELISTS");
            if ("true".equals(mEnlistDelists)) {
                multipleEnlistDelists = true;
                if (_logger.isLoggable(Level.FINE))
                    _logger.log(Level.FINE,"TM: multiple enlists, delists are enabled");
            }
            String maxEntriesValue
                = System.getProperty("JTA_RESOURCE_TABLE_MAX_ENTRIES");
            if (maxEntriesValue != null) {
                int temp = Integer.parseInt(maxEntriesValue);
                if (temp > 0) {
                    maxEntries = temp;
                }
            }
            String loadFactorValue
                = System.getProperty("JTA_RESOURCE_TABLE_DEFAULT_LOAD_FACTOR");
            if (loadFactorValue != null) {
                float f = Float.parseFloat(loadFactorValue);
                if (f > 0) {
                     loadFactor = f;
                }
            }
        } catch (Exception ex) {
            // ignore
        }

        resourceTable = new BaseCache();
        ((BaseCache)resourceTable).init(maxEntries, loadFactor, null);
        // END IASRI 4705808 TTT001

        if (habitat != null) {
            TransactionService txnService = habitat.getService(TransactionService.class,
                   ServerEnvironment.DEFAULT_INSTANCE_NAME);
            // running on the server side ?
            if (txnService != null) {
                transactionTimeout = Integer.parseInt(txnService.getTimeoutInSeconds());
                // the delegates will do the rest if they support it

                String v = txnService.getPropertyValue("purge-cancelled-transactions-after");
                if (v != null && v.length() > 0) {
                    purgeCancelledTtransactions = Integer.parseInt(v);
                }

                TransactionServiceConfigListener listener =
                        habitat.getService(TransactionServiceConfigListener.class);
                listener.setTM(this);
            }
            ModuleMonitoringLevels levels = habitat.getService(ModuleMonitoringLevels.class);
            // running on the server side ?
            if (levels != null) {
                String level = levels.getTransactionService();
                if (!("OFF".equals(level))) {
                    monitoringEnabled = true;
                }
            }
        }

        // ENF OF BUG 4665539
                if (_logger.isLoggable(Level.FINE))
                _logger.log(Level.FINE,"TM: Tx Timeout = " + transactionTimeout);

        // START IASRI 4705808 TTT004 -- monitor resource table stats
        try {
            // XXX TODO:
            if (Boolean.getBoolean("MONITOR_JTA_RESOURCE_TABLE_STATISTICS")) {
                registerStatisticMonitorTask();
            }

            StatsProviderManager.register(
                    "transaction-service", // element in domain.xml <monitoring-service>/<monitoring-level>
                    PluginPoint.SERVER, "transaction-service", // server.transaction-service node in asadmin get
                    new TransactionServiceStatsProvider(this, _logger));
        } catch (Exception ex) {
            // ignore
        }

        monitor = new TransactionServiceProbeProvider();
    }

    /**
     * Clears the transaction associated with the caller thread
     */
    public void clearThreadTx() {
        setCurrentTransaction(null);
        delegates.set(null);
    }

    /** {@inheritDoc}
    */
    public String getTxLogLocation() {
        return getDelegate().getTxLogLocation();
    }

    /** {@inheritDoc}
    */
    public void registerRecoveryResourceHandler(XAResource xaResource) {
        getDelegate().registerRecoveryResourceHandler(xaResource);
    }

/****************************************************************************/
/** Implementations of JavaEETransactionManager APIs **************************/
/****************************************************************************/

    /**
     * Return true if a "null transaction context" was received
     * from the client. See EJB2.0 spec section 19.6.2.1.
     * A null tx context has no Coordinator objref. It indicates
     * that the client had an active
     * tx but the client container did not support tx interop.
     */
    public boolean isNullTransaction() {
        return getDelegate().isNullTransaction();
    }

    public void shutdown() {
        _timer.cancel();
    }
    public void initRecovery(boolean force) {
        getDelegate().initRecovery(force);
    }

    public void recover(XAResource[] resourceList) {
        getDelegate().recover(resourceList);
    }

    public boolean enlistResource(Transaction tran, TransactionalResource h)
            throws RollbackException, IllegalStateException, SystemException {
        if ( !h.isTransactional() )
            return true;

        //If LazyEnlistment is suspended, do not enlist resource.
        if(h.isEnlistmentSuspended()){
            return false;
        }

       if (monitoringEnabled) {
           JavaEETransaction tx = getDelegate().getJavaEETransaction(tran);
           if ( tx != null ) {
               ((JavaEETransactionImpl)tx).addResourceName(h.getName());
           }
       }

       if ( !(tran instanceof JavaEETransaction) ) {
           return enlistXAResource(tran, h);
       }

       JavaEETransactionImpl tx = (JavaEETransactionImpl)tran;

       if(_logger.isLoggable(Level.FINE)) {
           _logger.log(Level.FINE,"\n\nIn JavaEETransactionManagerSimplified.enlistResource, h="
                   +h+" h.xares="+h.getXAResource()
                   /** +" h.alloc=" +h.getResourceAllocator() **/ +" tx="+tx);
       }

       JavaEETransactionManagerDelegate d = setDelegate();
       boolean useLAO = d.useLAO();

       if ( (tx.getNonXAResource()!=null) && (!useLAO || !h.supportsXA())) {
           boolean isSameRM=false;
           try {
               isSameRM = h.getXAResource().isSameRM(tx.getNonXAResource().getXAResource());
           } catch ( XAException xex ) {
               throw new SystemException(sm.getString("enterprise_distributedtx.samerm_excep",xex));
           } catch ( Exception ex ) {
               throw new SystemException(sm.getString("enterprise_distributedtx.samerm_excep",ex));
           }
           if ( !isSameRM ) {
               throw new IllegalStateException(sm.getString("enterprise_distributedtx.already_has_nonxa"));
           }
       }

       if ( h.supportsXA() ) {
           if (!d.supportsXAResource()) {
               throw new IllegalStateException(
                        sm.getString("enterprise_distributedtx.xaresource_not_supported"));
           }

           if ( tx.isLocalTx() ) {
               d.enlistLAOResource(tx, tx.getNonXAResource());

/** XXX TO BE MOVED TO XA DELEGATE XXX **
               startJTSTx(tx);

               //If transaction conatains a NonXA and no LAO, convert the existing
               //Non XA to LAO
               if(useLAO) {
                   if(tx.getNonXAResource()!=null && (tx.getLAOResource()==null) ) {
                       tx.setLAOResource(tx.getNonXAResource());
                       // XXX super.enlistLAOResource(tx, tx.getNonXAResource());
                   }
               }
** XXX TO BE MOVED TO XA DELEGATE XXX **/
           }
           return enlistXAResource(tx, h);
       } else { // non-XA resource
            if (tx.isImportedTransaction())
                throw new IllegalStateException(
                        sm.getString("enterprise_distributedtx.nonxa_usein_jts"));
            if (tx.getNonXAResource() == null) {
                tx.setNonXAResource(h);
            }
            if ( tx.isLocalTx() ) {
                // notify resource that it is being used for tx,
                // e.g. this allows the correct physical connection to be
                // swapped in for the logical connection.
                // The flags parameter can be 0 because the flags are not
                // used by the XAResource implementation for non-XA resources.
                try {
                    h.getXAResource().start(tx.getLocalXid(), 0);
                } catch ( XAException ex ) {
                    throw new RuntimeException(
                            sm.getString("enterprise_distributedtx.xaresource_start_excep"),ex);
                }

                h.enlistedInTransaction(tx);
                return true;
            } else {
                return d.enlistDistributedNonXAResource(tx, h);
/** XXX TO BE MOVED TO XA DELEGATE? XXX
                if(useLAO) {
                    return super.enlistResource(tx, h);
                } else {
                    throw new IllegalStateException(
                            sm.getString("enterprise_distributedtx.nonxa_usein_jts"));
                }
** XXX TO BE MOVED TO XA DELEGATE? XXX **/
            }
        }
    }

    public void unregisterComponentResource(TransactionalResource h) {
        Object instance = h.getComponentInstance();
        if (instance == null) return;
        h.setComponentInstance(null);
        ComponentInvocation inv = invMgr.getCurrentInvocation();
        List l = getExistingResourceList(instance, inv);

        if (l != null) {
            l.remove(h);
        }
    }

    public void startJTSTx(JavaEETransaction t)
            throws RollbackException, IllegalStateException, SystemException {

        JavaEETransactionImpl tx = (JavaEETransactionImpl)t;
        TransactionInternal jtsTx = getDelegate().startJTSTx(tx, tx.isAssociatedTimeout());

        // The local Transaction was promoted to global Transaction
        if (monitoringEnabled){
            if(activeTransactions.remove(tx)){
                monitor.transactionDeactivatedEvent();
            }
        }

        tx.setJTSTx(jtsTx);
        jtsTx.registerSynchronization(new JTSSynchronization(jtsTx, this));
    }

    /**
     * get the resources being used in the calling component's invocation context
     * @param instance Calling component instance
     * @param inv Calling component's invocation information
     * @return List of resources
     */
    public List getResourceList(Object instance, ComponentInvocation inv) {
        if (inv == null)
            return new ArrayList(0);
        List l = null;

/** XXX EJB CONTAINER ONLY XXX -- NEED TO CHECK THE NEW CODE BELOW **
        if (inv.getInvocationType() ==
                ComponentInvocation.ComponentInvocationType.EJB_INVOCATION) {
            ComponentContext ctx = inv.context;
            if (ctx != null)
                l = ctx.getResourceList();
            else {
                l = new ArrayList(0);
            }
        }
** XXX EJB CONTAINER ONLY XXX **/

        ResourceHandler rh = inv.getResourceHandler();
        if (rh != null) {
            l = rh.getResourceList();
            if (l == null) {
                l = new ArrayList(0);
            }
        }
        else {
            Object key = getResourceTableKey(instance, inv);
            if (key == null)
                return new ArrayList(0);
            l = (List) resourceTable.get(key);
            if (l == null) {
                l = new ArrayList(); //FIXME: use an optimum size?
                resourceTable.put(key, l);
            }
        }
        return l;
    }

    public void enlistComponentResources() throws RemoteException {
        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE,"TM: enlistComponentResources");

        ComponentInvocation inv = invMgr.getCurrentInvocation();
        if (inv == null)
            return;
        try {
            Transaction tran = getTransaction();
            inv.setTransaction((JavaEETransaction)tran);
            enlistComponentResources(inv);
        } catch (InvocationException ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.excep_in_enlist" ,ex);
            throw new RemoteException(ex.getMessage(), ex.getNestedException());
        } catch (Exception ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.excep_in_enlist" ,ex);
            throw new RemoteException(ex.getMessage(), ex);
        }
    }

    public boolean delistResource(Transaction tran, TransactionalResource h, int flag)
            throws IllegalStateException, SystemException {
        if (!h.isTransactional()) return true;

        if ( !(tran instanceof JavaEETransaction) )
            return delistJTSResource(tran, h, flag);

        JavaEETransactionImpl tx = (JavaEETransactionImpl)tran;
        if ( tx.isLocalTx() ) {
            // dissociate resource from tx
            try {
                h.getXAResource().end(tx.getLocalXid(), flag);
            } catch ( XAException ex ) {
                throw new RuntimeException(sm.getString("enterprise_distributedtx.xaresource_end_excep", ex));
            }
            return true;
        }
        else
            return delistJTSResource(tran, h, flag);
    }

    public void delistComponentResources(boolean suspend)
            throws RemoteException {
        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE,"TM: delistComponentResources");
        ComponentInvocation inv = invMgr.getCurrentInvocation();
        // BEGIN IASRI# 4646060
        if (inv == null) {
            return;
        }
        // END IASRI# 4646060
        try {
            delistComponentResources(inv, suspend);
        } catch (InvocationException ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.excep_in_delist",ex);
            throw new RemoteException("", ex.getNestedException());
        } catch (Exception ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.excep_in_delist",ex);
            throw new RemoteException("", ex);
        }
    }


    public void registerComponentResource(TransactionalResource h) {
        ComponentInvocation inv = invMgr.getCurrentInvocation();
        if (inv != null) {
            Object instance = inv.getInstance();
            if (instance == null) return;
            h.setComponentInstance(instance);
            List l = getResourceList(instance, inv);
            l.add(h);
        }
    }

    private JavaEETransactionImpl initJavaEETransaction(int timeout) {
        JavaEETransactionImpl tx = null;
        // Do not need to use injection.
        if (timeout > 0)
            tx = new JavaEETransactionImpl(timeout, this);
        else
            tx = new JavaEETransactionImpl(this);

        setCurrentTransaction(tx);
        return tx;
    }

    public List getExistingResourceList(Object instance, ComponentInvocation inv) {
       if (inv == null)
           return null;
        List l = null;

/** XXX EJB CONTAINER ONLY XXX -- NEED TO CHECK THE NEW CODE BELOW **
        if (inv.getInvocationType() ==
                ComponentInvocation.ComponentInvocationType.EJB_INVOCATION) {
            ComponentContext ctx = inv.context;
            if (ctx != null)
                l = ctx.getResourceList();
            return l;
        }
** XXX EJB CONTAINER ONLY XXX **/

        ResourceHandler rh = inv.getResourceHandler();
        if (rh != null) {
            l = rh.getResourceList();
        }
        else {
            Object key = getResourceTableKey(instance, inv);
            if (key != null)
                l =  (List) resourceTable.get(key);
        }
        return l;
    }

    public void preInvoke(ComponentInvocation prev)
            throws InvocationException {
        if ( prev != null && prev.getTransaction() != null &&
            prev.isTransactionCompleting() == false) {
            // do not worry about delisting previous invocation resources
            // if transaction is being completed
            delistComponentResources(prev, true)// delist with TMSUSPEND
        }

    }

    public void postInvoke(ComponentInvocation curr, ComponentInvocation prev)
            throws InvocationException {

        if ( curr != null && curr.getTransaction() != null )
            delistComponentResources(curr, false)// delist with TMSUCCESS
        if ( prev != null && prev.getTransaction() != null &&
                prev.isTransactionCompleting() == false) {
            // do not worry about re-enlisting previous invocation resources
            // if transaction is being completed
            enlistComponentResources(prev);
        }

    }

    public void componentDestroyed(Object instance) {
        componentDestroyed(instance, null);
    }

    public void componentDestroyed(Object instance, ComponentInvocation inv) {
        if (_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE,"TM: componentDestroyed" + instance);
            _logger.log(Level.FINE,"TM: resourceTable before: " + resourceTable.getEntryCount());
        }

        // Access resourceTable directly to avoid adding an empty list then removing it
        List l = (List)resourceTable.remove(getResourceTableKey(instance, inv));
        processResourceList(l);

        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE,"TM: resourceTable after: " + resourceTable.getEntryCount());
    }

    public void componentDestroyed(ResourceHandler rh) {
        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE, " componentDestroyed: " + rh);

        if (rh != null) {
            processResourceList(rh.getResourceList());
        }
    }

    public boolean isTimedOut() {
        JavaEETransaction tx = transactions.get();
        if ( tx != null)
            return tx.isTimedOut();
        else
            return false;
    }

    /**
     * Called from the CORBA Interceptors on the server-side when
     * the server is replying to the client (local + remote client).
     * Check if there is an active transaction and remove it from TLS.
     */
    public void checkTransactionImport() {
        // First check if this is a local call
        int[] count = (int[])localCallCounter.get();
        if ( count != null && count[0] > 0 ) {
            count[0]--;
            return;
        }
        else {
            // A remote call, clear TLS so that if this thread is reused
            // later, the current tx doesnt hang around.
            clearThreadTx();
        }
    }

    /**
     * Called from the CORBA Interceptors on the client-side when
     * a client makes a call to a remote object (not in the same JVM).
     * Check if there is an active, exportable transaction.
     * @exception RuntimeException if the transaction is not exportable
     */
    public void checkTransactionExport(boolean isLocal) {

        if ( isLocal ) {
            // Put a counter in TLS indicating this is a local call.
            // Use int[1] as a mutable java.lang.Integer!
            int[] count = (int[])localCallCounter.get();
            if ( count == null ) {
                count = new int[1];
                localCallCounter.set(count);
            }
            count[0]++;
            return;
        }

        JavaEETransaction tx = transactions.get();
        if ( tx == null )
            return;

        if ( !tx.isLocalTx() ) // a JTS tx, can be exported
            return;

        // Check if a local tx with non-XA resource is being exported.
        // XXX what if this is a call on a non-transactional remote object ?
        if ( tx.getNonXAResource() != null )
            throw new RuntimeException(sm.getString("enterprise_distributedtx.cannot_export_transaction_having_nonxa"));

        // If we came here, it means we have a local tx with no registered
        // resources, so start a JTS tx which can be exported.
        try {
            startJTSTx(tx);
        } catch ( RollbackException rlex ) {
            throw new RuntimeException(sm.getString("enterprise_distributedtx.unable_tostart_JTSTransaction"),rlex);
        } catch ( IllegalStateException isex ) {
            throw new RuntimeException(sm.getString("enterprise_distributedtx.unable_tostart_JTSTransaction"),isex);
        } catch ( SystemException ex ) {
            throw new RuntimeException(sm.getString("enterprise_distributedtx.unable_tostart_JTSTransaction"),ex);
        } catch ( Exception excep ) {
            throw new RuntimeException(sm.getString("enterprise_distributedtx.unable_tostart_JTSTransaction"),excep);
        }
    }

    /**
     * This is used by importing transactions via the Connector contract.
     * Should not be called
     *
     * @return a <code>XATerminator</code> instance.
     * @throws UnsupportedOperationException
     */
    public XATerminator getXATerminator() {
        return getDelegate().getXATerminator();
    }

    /**
     * Release a transaction. This call causes the calling thread to be
     * dissociated from the specified transaction. <p>
     * This is used by importing transactions via the Connector contract.
     *
     * @param xid the Xid object representing a transaction.
     */
    public void release(Xid xid) throws WorkException {
        getDelegate().release(xid);
    }

    /**
     * Recreate a transaction based on the Xid. This call causes the calling
     * thread to be associated with the specified transaction. <p>
     * This is used by importing transactions via the Connector contract.
     *
     * @param xid the Xid object representing a transaction.
     */
    public void recreate(Xid xid, long timeout) throws WorkException {
        getDelegate().recreate(xid, timeout);
    }

/****************************************************************************/
/** Implementations of JTA TransactionManager APIs **************************/
/****************************************************************************/

    public void registerSynchronization(Synchronization sync)
            throws IllegalStateException, SystemException {
        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE,"TM: registerSynchronization");

        try {
            Transaction tran = getTransaction();
            if (tran != null) {
                tran.registerSynchronization(sync);
            }
        } catch (RollbackException ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.rollbackexcep_in_regsynch",ex);
            throw new IllegalStateException();
        }
    }

   // Implementation of begin() is moved to begin(int timeout)
   public void begin() throws NotSupportedException, SystemException {
       begin(getEffectiveTimeout());
   }

   /**
    * This method is introduced as part of implementing the local transaction timeout
    * capability. Implementation of begin() moved here. Previpusly there is no timeout
    * infrastructure for local txns, so when ever a timeout required for local txn, it
    * uses the globaltxn timeout infrastructure by doing an XA simulation.  
    **/
   public void begin(int timeout) throws NotSupportedException, SystemException {
       // Check if tx already exists
       if ( transactions.get() != null )
           throw new NotSupportedException(sm.getString("enterprise_distributedtx.notsupported_nested_transaction"));

       setDelegate();

       // Check if JTS tx exists, without starting JTS tx.
       // This is needed in case the JTS tx was imported from a client.
       if ( getStatus() != Status.STATUS_NO_TRANSACTION )
           throw new NotSupportedException(sm.getString("enterprise_distributedtx.notsupported_nested_transaction"));

        // START IASRI 4662745
        if(monitoringEnabled){
            getDelegate().getReadLock().lock(); // XXX acquireReadLock();
            try{
                JavaEETransactionImpl tx = initJavaEETransaction(timeout);
                activeTransactions.add(tx);
                monitor.transactionActivatedEvent();
                ComponentInvocation inv = invMgr.getCurrentInvocation();
                if (inv != null && inv.getInstance() != null) {
                    tx.setComponentName(inv.getInstance().getClass().getName());
                }
            }finally{
                getDelegate().getReadLock().unlock(); // XXX releaseReadLock();
            }
        } else {
            initJavaEETransaction(timeout);
        }
        // START IASRI 4662745
    }

    public void commit() throws RollbackException,
            HeuristicMixedException, HeuristicRollbackException, SecurityException,
            IllegalStateException, SystemException {

        boolean acquiredlock=false;
        try {
            JavaEETransaction tx = transactions.get();
            if ( tx != null && tx.isLocalTx()) {
                if(monitoringEnabled){
                    getDelegate().getReadLock().lock(); // XXX acquireReadLock();
                    acquiredlock = true;
                }
                tx.commit(); // commit local tx
            }
            else  {
                try{
                    // an XA transaction
                    getDelegate().commitDistributedTransaction();
                }finally{
                    if ( tx != null ) {
                        ((JavaEETransactionImpl)tx).onTxCompletion(true);
                    }
                }
            }

        } finally {
            setCurrentTransaction(null); // clear current thread's tx
            delegates.set(null);
            if(acquiredlock){
                getDelegate().getReadLock().unlock(); // XXX releaseReadLock();
            }
        }
        // END IASRI 4662745
    }

    public void rollback() throws IllegalStateException, SecurityException,
                SystemException {
        boolean acquiredlock=false;
        try {
            JavaEETransaction tx = transactions.get();
            if ( tx != null && tx.isLocalTx()) {
                if(monitoringEnabled){
                    getDelegate().getReadLock().lock(); // XXX acquireReadLock();
                    acquiredlock = true;
                }
                tx.rollback(); // rollback local tx
            }
            else  {
                try {
                    // an XA transaction
                    getDelegate().rollbackDistributedTransaction();
                }finally{
                    if ( tx != null ) {
                        ((JavaEETransactionImpl)tx).onTxCompletion(false);
                    }
                }
            }

        } finally {
            setCurrentTransaction(null); // clear current thread's tx
            delegates.set(null);
            if(acquiredlock){
                getDelegate().getReadLock().unlock(); // XXX releaseReadLock();
            }
        }
    }


    public int getStatus() throws SystemException {
        return getDelegate().getStatus();
    }

    public Transaction getTransaction() throws SystemException {
        return getDelegate().getTransaction();

/** XXX CHECK WHAT'S NEEDED FOR XA DELEGATE XXX **
            TransactionInternal jtsTx = super.getTransaction();
            if ( jtsTx == null )
                return null;
            else {
                // check if this JTS Transaction was previously active
                // in this JVM (possible for distributed loopbacks).
                tx = (JavaEETransaction)globalTransactions.get(jtsTx);
                if ( tx == null ) {
                    tx = new JavaEETransaction(jtsTx, this);
                    try {
                        jtsTx.registerSynchronization(
                                new JTSSynchronization(jtsTx, this));
                    } catch ( RollbackException rlex ) {
                        throw new SystemException(rlex.toString());
                    } catch ( IllegalStateException isex ) {
                        throw new SystemException(isex.toString());
                    } catch ( Exception ex ) {
                        throw new SystemException(ex.toString());
                    }

                    globalTransactions.put(jtsTx, tx);
                }
                setCurrentTransaction(tx); // associate tx with thread
                return tx;
            }
** XXX CHECK WHAT'S NEEDED FOR XA DELEGATE XXX **/
    }

    public void setRollbackOnly()
        throws IllegalStateException, SystemException {

        JavaEETransaction tx = transactions.get();
        // START IASRI 4662745
        if ( tx != null && tx.isLocalTx()){
            if(monitoringEnabled){
                getDelegate().getReadLock().lock(); // XXX acquireReadLock();
                try{
                    tx.setRollbackOnly();
                }finally{
                    getDelegate().getReadLock().unlock(); // XXX releaseReadLock();
                }
            } else {
                tx.setRollbackOnly();
            }
        }
        else
            getDelegate().setRollbackOnlyDistributedTransaction(); // probably a JTS imported tx
    }

    public Transaction suspend() throws SystemException {
        return getDelegate().suspend(transactions.get());

/** XXX TO BE MOVED TO DELEGATES XXX **
        if ( tx != null ) {
            if ( !tx.isLocalTx() )
                super.suspend();

            setCurrentTransaction(null);
            return tx;
        }
        else {
            return super.suspend(); // probably a JTS imported tx
        }
** XXX TO BE MOVED TO DELEGATES XXX **/
    }

    public void resume(Transaction tobj)
            throws InvalidTransactionException, IllegalStateException,
            SystemException {

        JavaEETransaction tx = transactions.get();
        if ( tx != null )
            throw new IllegalStateException(
                    sm.getString("enterprise_distributedtx.transaction_exist_on_currentThread"));

        if ( tobj != null ) {
            int status = tobj.getStatus();
            if (status == Status.STATUS_ROLLEDBACK ||
                    status == Status.STATUS_COMMITTED ||
                    status == Status.STATUS_NO_TRANSACTION ||
                    status == Status.STATUS_UNKNOWN) {
                throw new InvalidTransactionException(sm.getString(
                    "enterprise_distributedtx.resume_invalid_transaction", tobj));
            }
        } else {
            throw new InvalidTransactionException(sm.getString(
                    "enterprise_distributedtx.resume_invalid_transaction", "null"));
        }

        if ( tobj instanceof JavaEETransactionImpl ) {
            JavaEETransactionImpl javaEETx = (JavaEETransactionImpl)tobj;
            if ( !javaEETx.isLocalTx() )
                getDelegate().resume(javaEETx.getJTSTx());

            setCurrentTransaction(javaEETx);
        }
        else {
            getDelegate().resume(tobj); // probably a JTS imported tx
        }
    }

    /**
     * Modify the value of the timeout value that is associated with the
     * transactions started by the current thread with the begin method.
     *
     * <p> If an application has not called this method, the transaction
     * service uses some default value for the transaction timeout.
     *
     * @exception SystemException Thrown if the transaction manager
     *    encounters an unexpected error condition
     *
     */
    public void setTransactionTimeout(int seconds) throws SystemException {
        if (seconds < 0) {
            throw new SystemException(sm.getString("enterprise_distributedtx.invalid_timeout"));
        }

        txnTmout.set(seconds);
        // transactionTimeout = seconds;
    }

    /**
     * Modify the value to be used to purge transaction tasks after the
     * specified number of cancelled tasks.
     */
    public void setPurgeCancelledTtransactionsAfter(int num) {
        purgeCancelledTtransactions = num;
    }

    /**
     * Returns the value to be used to purge transaction tasks after the
     * specified number of cancelled tasks.
     */
    public int getPurgeCancelledTtransactionsAfter() {
        return purgeCancelledTtransactions;
    }

    public JavaEETransaction getCurrentTransaction() {
        return transactions.get();
    }

    public void setCurrentTransaction(JavaEETransaction t) {
        transactions.set(t);
    }

    public XAResourceWrapper getXAResourceWrapper(String clName) {
        return getDelegate().getXAResourceWrapper(clName);
    }

    public void handlePropertyUpdate(String name, Object value) {
        delegate.handlePropertyUpdate(name, value);
        // XXX Check if the current delegate needs to be called as well.
    }

    public boolean recoverIncompleteTx(boolean delegated, String logPath,
            XAResource[] xaresArray) throws Exception {
        return delegate.recoverIncompleteTx(delegated, logPath, xaresArray);
    }

/****************************************************************************/
/*********************** Called by Admin Framework **************************/
/****************************************************************************/
   /*
    * Called by Admin Framework to freeze the transactions.
    */
    public synchronized void freeze(){
        getDelegate().acquireWriteLock();
        monitor.freezeEvent(true);
    }
    /*
     * Called by Admin Framework to freeze the transactions.
     * These undoes the work done by the freeze.
     */
    public synchronized void unfreeze(){
        getDelegate().releaseWriteLock();
        monitor.freezeEvent(false);
    }

    /** XXX ???
     */
    public boolean isFrozen() {
        return getDelegate().isWriteLocked();
    }

    public void cleanTxnTimeout() {
        txnTmout.set(null);
    }

    public int getEffectiveTimeout() {
        Integer tmout = txnTmout.get();
        if (tmout ==  null) {
            return transactionTimeout;
        }
        else {
            return tmout;
        }
    }

    public void setDefaultTransactionTimeout(int seconds) {
        if (seconds < 0) seconds = 0;
        transactionTimeout = seconds;
    }

   /*
    *  This method returns the details of the Currently Active Transactions
    *  Called by Admin Framework when transaction monitoring is enabled
    *  @return ArrayList of TransactionAdminBean
    *  @see TransactionAdminBean
    */
    public ArrayList getActiveTransactions() {
        ArrayList tranBeans = new ArrayList();
        txnTable = new Hashtable();
        Object[] activeCopy = activeTransactions.toArray(); // get the clone of the active transactions
        for(int i=0;i<activeCopy.length;i++){
            try{
                Transaction tran = (Transaction)activeCopy[i];
                TransactionAdminBean tBean = getDelegate().getTransactionAdminBean(tran);
                if (tBean == null) {
                    // Shouldn't happen
                    _logger.warning("enterprise_distributedtx.txbean_null" + tran);
                } else {
                    if (_logger.isLoggable(Level.FINE))
                        _logger.log(Level.FINE,"TM: Adding txnId " + tBean.getId() + " to txnTable");

                    txnTable.put(tBean.getId(), tran);
                    tranBeans.add(tBean);
                }
            }catch(Exception ex){
                _logger.log(Level.SEVERE,
                    "transaction.monitor.error_while_getting_monitor_attr", ex);
            }
        }
        return tranBeans;
    }

    public TransactionAdminBean getTransactionAdminBean(Transaction tran)
            throws javax.transaction.SystemException {

        TransactionAdminBean tBean = null;
        if(tran instanceof JavaEETransaction){
            JavaEETransactionImpl tran1 = (JavaEETransactionImpl)tran;
            String id = tran1.getTransactionId();
            long startTime = tran1.getStartTime();
            String componentName = tran1.getComponentName();
            ArrayList<String> resourceNames = tran1.getResourceNames();
            long elapsedTime = System.currentTimeMillis()-startTime;
            String status = getStatusAsString(tran.getStatus());

            tBean = new TransactionAdminBean(tran, id, status, elapsedTime,
                     componentName, resourceNames);
        }

        return tBean;
    }

    /*
     *  Called by Admin Framework when transaction monitoring is enabled
     */
    public void forceRollback(String txnId) throws IllegalStateException, SystemException{
         // XXX - WORK AROUND MONITORING BUG
         if (txnTable == null || txnTable.size() == 0)
             getActiveTransactions();
         // XXX - WORK AROUND MONITORING BUG

         if (txnTable == null || txnTable.get(txnId) == null) {
            String result = sm.getString("transaction.monitor.rollback_invalid_id");
            throw new  IllegalStateException(result);
        } else {
            if (_logger.isLoggable(Level.FINE))
                _logger.log(Level.FINE,"TM: Marking txnId " + txnId + " for rollback");

             ((Transaction) txnTable.get(txnId)).setRollbackOnly();
         }

    }

    public void setMonitoringEnabled(boolean enabled){
        monitoringEnabled = enabled;
        //reset the variables
        activeTransactions.clear();
    }

    private void _monitorTxCompleted(Object obj, boolean committed){
        if(obj != null) {
            if (obj instanceof JavaEETransactionImpl) {
                JavaEETransactionImpl t = (JavaEETransactionImpl) obj;
                if (!t.isLocalTx()) {
                    obj = t.getJTSTx();
                }
            }
            if(activeTransactions.remove(obj)) {
                if(committed){
                    monitor.transactionCommittedEvent();
                }else{
                    monitor.transactionRolledbackEvent();
                }
            } else {
                // WARN ???
            }
        }
    }

    // Mods: Adding method for statistic dumps using TimerTask
    private void registerStatisticMonitorTask() {
        TimerTask task = new StatisticMonitorTask();
        // for now, get monitoring interval from system prop
        int statInterval = 2 * 60 * 1000;
        try {
            String interval
                = System.getProperty("MONITOR_JTA_RESOURCE_TABLE_SECONDS");
            int temp = Integer.parseInt(interval);
            if (temp > 0) {
                statInterval = temp;
            }
        } catch (Exception ex) {
            // ignore
        }

        _timer.scheduleAtFixedRate(task, 0, statInterval);
    }

    // Mods: Adding TimerTask class for statistic dumps
    class StatisticMonitorTask extends TimerTask {
        public void run() {
            if (resourceTable != null) {
                Map stats = resourceTable.getStats();
                Iterator it = stats.entrySet().iterator();
                _logger.log(Level.INFO,
                        "********** JavaEETransactionManager resourceTable stats *****");
                while (it.hasNext()) {
                    Map.Entry entry = (Map.Entry)it.next();
                    _logger.log(Level.INFO, (String)entry.getKey() + ": " + entry.getValue());
                }
            }
        }
    }

/****************************************************************************/
/************************* Helper Methods ***********************************/
/****************************************************************************/
    public static String getStatusAsString(int status) {
        return (String)statusMap.get(status);
    }

    private void delistComponentResources(ComponentInvocation inv,
                                          boolean suspend)
        throws InvocationException {

        try {
            Transaction tran = (Transaction) inv.getTransaction();
            if (isTransactionActive(tran)) {
                List l = getExistingResourceList(inv.getInstance(), inv);
                if (l == null || l.size() == 0)
                    return;

                int flag = (suspend)? XAResource.TMSUSPEND : XAResource.TMSUCCESS;
                Iterator it = l.iterator();
                while(it.hasNext()){
                    TransactionalResource h = (TransactionalResource)it.next();
                    try{
                        if ( h.isEnlisted() ) {
                            delistResource(tran, h, flag);
                        }
                    } catch (IllegalStateException ex) {
                        if (_logger.isLoggable(Level.FINE))
                            _logger.log(Level.FINE,"TM: Exception in delistResource", ex);
                        // ignore error due to tx time out
                    }catch(Exception ex){
                        if (_logger.isLoggable(Level.FINE))
                            _logger.log(Level.FINE,"TM: Exception in delistResource", ex);
                        it.remove();
                        handleResourceError(h, ex, tran);
                    }
                }
                //END OF IASRI 4658504
            }
        } catch (Exception ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.excep_in_delist",ex);
        }
    }

    protected boolean enlistXAResource(Transaction tran, TransactionalResource h)
            throws RollbackException, IllegalStateException, SystemException {

        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE,"TM: enlistResource");

        if (resourceEnlistable(h)) {
            XAResource res = h.getXAResource();
            boolean result = tran.enlistResource(res);
            if (!h.isEnlisted())
                h.enlistedInTransaction(tran);
            return result;
        } else {
            return true;
        }
    }

    private void enlistComponentResources(ComponentInvocation inv)
    throws InvocationException {

        try {
            Transaction tran = (Transaction) inv.getTransaction();
            if (isTransactionActive(tran)) {
                List l = getExistingResourceList(inv.getInstance(), inv);
                if (l == null || l.size() == 0) return;
                Iterator it = l.iterator();
                // END IASRI 4705808 TTT002
                while(it.hasNext()) {
                    TransactionalResource h = (TransactionalResource) it.next();
                    try{
                        enlistResource(tran,h);
                    }catch(Exception ex){
                        it.remove();
                        handleResourceError(h,ex,tran);
                    }
                }
                //END OF IASRI 4658504
            }
        } catch (Exception ex) {
            _logger.log(Level.SEVERE,"enterprise_distributedtx.excep_in_enlist",ex);
        }
    }

    /**
     * Called by #componentDestroyed()
     */
    private void processResourceList(List l) {
        if (l != null && l.size() > 0) {
            Iterator it = l.iterator();
            while (it.hasNext()) {
                TransactionalResource h = (TransactionalResource) it.next();
                try {
                    h.closeUserConnection();
                } catch (Exception ex) {
                    if (_logger.isLoggable(Level.FINE))
                        _logger.log(Level.WARNING,"enterprise_distributedtx.pooling_excep", ex);
                }
            }
            l.clear();
        }
    }

    private void handleResourceError(TransactionalResource h,
                                     Exception ex, Transaction tran) {

        if (_logger.isLoggable(Level.FINE)) {
            if (h.isTransactional()) {
                _logger.log(Level.FINE,"TM: HandleResourceError " +
                                   h.getXAResource() +
                                   "," + ex);
            }
        }
        try {
            if (tran != null && h.isTransactional() && h.isEnlisted() ) {
                tran.delistResource(h.getXAResource(), XAResource.TMSUCCESS);
            }
        } catch (Exception ex2) {
            // ignore
        }


        if (ex instanceof RollbackException) {
            // transaction marked as rollback
            return;
        } else if (ex instanceof IllegalStateException) {
            // transaction aborted by time out
            // close resource
            try {
                h.closeUserConnection();
            } catch (Exception ex2) {
                //Log.err.println(ex2);
            }
        } else {
            // destroy resource. RM Error.
            try {
                h.destroyResource();
            } catch (Exception ex2) {
                //Log.err.println(ex2);
            }
        }
    }

    private Object getResourceTableKey(Object instance, ComponentInvocation inv) {
        Object key = null;
        if ( inv != null) {
            key = inv.getResourceTableKey();
        }

        // If ComponentInvocation is null or doesn't hold the key,
        // use instance as the key.
        if (key == null) {
            key = instance;
        }
        return key;
    }

    private boolean isTransactionActive(Transaction tran) {
        return (tran != null);
    }

    /**
     * JTS version of the #delistResource
     * @param suspend true if the transaction association should
     * be suspended rather than ended.
     */
    private boolean delistJTSResource(Transaction tran, TransactionalResource h,
                                  int flag)
        throws IllegalStateException, SystemException {

// ** XXX Throw an exception instead ??? XXX **
        if (_logger.isLoggable(Level.FINE))
            _logger.log(Level.FINE,"TM: delistResource");

        if (!h.isShareable() || multipleEnlistDelists) {
            if (h.isTransactional() && h.isEnlisted()) {
                return tran.delistResource(h.getXAResource(), flag);
            } else {
                return true;
            }
        }
        return true;
    }

    private void remove(Transaction tx) {
        getDelegate().removeTransaction(tx);

/** XXX TO BE MOVED TO XA DELEGATE XXX
        javaEETM.globalTransactions.remove(jtsTx);
** XXX TO BE MOVED TO XA DELEGATE XXX **/
    }

    /**
     * Called by JavaEETransactionImpl also
     */
    JavaEETransactionManagerDelegate getDelegate() {
        JavaEETransactionManagerDelegate d = delegates.get();
        return (d == null)? delegate : d;
    }

    private JavaEETransactionManagerDelegate setDelegate() {
        JavaEETransactionManagerDelegate d = delegates.get();
        if (d == null) {
            d = delegate;
            delegates.set(d);
        }

        return d;
    }

    public boolean isDelegate(JavaEETransactionManagerDelegate d) {
        if (delegate == null)
            return false;

        return (d.getClass().getName().equals(delegate.getClass().getName()));
    }

    private void initDelegates() {
        if (habitat == null)
            return; // the delegate will be set explicitly

        for (JavaEETransactionManagerDelegate d :
                habitat.<JavaEETransactionManagerDelegate>getAllServices(JavaEETransactionManagerDelegate.class)) {
            setDelegate(d);
        }

        if (delegate != null && _logger.isLoggable(Level.FINE))
          _logger.log(Level.INFO, "enterprise_used_delegate_name", delegate.getClass().getName());
               
    }

    public synchronized void setDelegate(JavaEETransactionManagerDelegate d) {
        // XXX Check if it's valid to set or if we need to remember all that asked.

        int curr = 0;
        if (delegate != null) {
            curr = delegate.getOrder();
        }
        if (d.getOrder() > curr) {
            delegate = d;

            // XXX Hk2 work around XXX
            delegate.setTransactionManager(this);

            if (_logger.isLoggable(Level.FINE))
                    _logger.log(Level.FINE,"Replaced delegate with "
                            + d.getClass().getName());
        }
    }

    public Logger getLogger() {
        return _logger;
    }

    public void monitorTxCompleted(Object obj, boolean b) {
        if(monitoringEnabled){
            _monitorTxCompleted(obj, b);
        }
    }

    public void monitorTxBegin(Transaction tx) {
        if (monitoringEnabled) {
            activeTransactions.add(tx);
            monitor.transactionActivatedEvent();
        }
    }

    public boolean resourceEnlistable(TransactionalResource h) {
        return (h.isTransactional() &&
                (!h.isEnlisted() || !h.isShareable() || multipleEnlistDelists));
    }

    public boolean isInvocationStackEmpty() {
        return (invMgr == null || invMgr.isInvocationStackEmpty());
    }

    public void setTransactionCompeting(boolean b) {
        ComponentInvocation curr = invMgr.getCurrentInvocation();
        if (curr != null)
            curr.setTransactionCompeting(b);
    }
   
    public JavaEETransaction createImportedTransaction(TransactionInternal jtsTx)
            throws SystemException {
        JavaEETransactionImpl tx = new JavaEETransactionImpl(jtsTx, this);
        try {
            jtsTx.registerSynchronization(
                    new JTSSynchronization(jtsTx, this));
        } catch ( RollbackException rlex ) {
            throw new SystemException(rlex.toString());
        } catch ( IllegalStateException isex ) {
            throw new SystemException(isex.toString());
        } catch ( Exception ex ) {
            throw new SystemException(ex.toString());
        }

        return tx;
    }

/****************************************************************************/
/** Implementation of javax.transaction.Synchronization *********************/
/****************************************************************************/
    private static class JTSSynchronization implements Synchronization {
        private TransactionInternal jtsTx;
        private JavaEETransactionManagerSimplified javaEETM;
   
        JTSSynchronization(TransactionInternal jtsTx,
                JavaEETransactionManagerSimplified javaEETM){
            this.jtsTx = jtsTx;
            this.javaEETM = javaEETM;
        }

        public void beforeCompletion() {}

        public void afterCompletion(int status) {
            javaEETM.remove(jtsTx);
        }
    }
}
TOP

Related Classes of com.sun.enterprise.transaction.JavaEETransactionManagerSimplified

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.