All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.transaction.JavaEETransactionManagerSimplified Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2013 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.
 */

// Portions Copyright [2016-2021] [Payara Foundation and/or its affiliates.]

package com.sun.enterprise.transaction;

import com.sun.appserv.util.cache.BaseCache;
import com.sun.appserv.util.cache.Cache;
import com.sun.enterprise.config.serverbeans.ModuleMonitoringLevels;
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.monitoring.TransactionServiceProbeProvider;
import com.sun.enterprise.transaction.monitoring.TransactionServiceStatsProvider;
import com.sun.enterprise.transaction.spi.JavaEETransactionManagerDelegate;
import com.sun.enterprise.transaction.spi.TransactionInternal;
import com.sun.enterprise.transaction.spi.TransactionalResource;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.logging.LogDomains;
import fish.payara.notification.requesttracing.RequestTraceSpanLog;
import fish.payara.nucleus.requesttracing.RequestTracingService;
import fish.payara.opentracing.OpenTracingService;
import io.opentracing.Span;
import io.opentracing.Tracer;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.InvocationException;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.api.invocation.ResourceHandler;
import org.glassfish.common.util.Constants;
import org.glassfish.external.probe.provider.PluginPoint;
import org.glassfish.external.probe.provider.StatsProviderManager;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.Rank;
import org.glassfish.hk2.api.ServiceLocator;
import org.jvnet.hk2.annotations.ContractsProvided;
import org.jvnet.hk2.annotations.Service;

import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.resource.spi.XATerminator;
import jakarta.resource.spi.work.WorkException;
import jakarta.transaction.*;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import java.rmi.RemoteException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Implementation of jakarta.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;

    @Inject private Provider openTracingServiceProvider;

    @Inject private Provider requestTracing;

    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 final ThreadLocal transactions;

    private final ThreadLocal localCallCounter;
    private final ThreadLocal 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 final ThreadLocal txnTmout = new ThreadLocal<>();

    private int purgeCancelledTtransactions = 0;

    // admin and monitoring related parameters
    private  static final Map statusMap = new HashMap<>();
    private final List activeTransactions = Collections.synchronizedList(new ArrayList<>());
    private boolean monitoringEnabled = false;
    private ScheduledFuture statisticsMonitoringFuture;

    private TransactionServiceProbeProvider monitor;
    private Map txnTable = null;

    private Cache resourceTable;

    private final ScheduledThreadPoolExecutor scheduledTransactionManagerExecutor;

    private final AtomicLong scheduledTransactionTimeouts = new AtomicLong(0);
    private volatile long scheduledTransactionTimeoutsAtLastPurge = 0;
    private ScheduledFuture purgeScheduledTransactionsFuture;

    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<>();
        localCallCounter = new ThreadLocal<>();
        delegates = new ThreadLocal<>();
        scheduledTransactionManagerExecutor = new ScheduledThreadPoolExecutor(
            Math.min(Runtime.getRuntime().availableProcessors(), 3)
        );
        if (getPurgeCancelledTtransactionsAfter() > 0) {
            purgeScheduledTransactionsFuture = scheduledTransactionManagerExecutor.scheduleAtFixedRate(
                    this::purgeCancelledTransactionTimeouts, 5, 5, TimeUnit.SECONDS
            );
        }
    }

    private void purgeCancelledTransactionTimeouts() {
        long currentTransactionTimeouts = scheduledTransactionTimeouts.get();
        if(currentTransactionTimeouts - scheduledTransactionTimeoutsAtLastPurge >= getPurgeCancelledTtransactionsAfter()) {
            scheduledTransactionTimeoutsAtLastPurge = currentTransactionTimeouts;
            scheduledTransactionManagerExecutor.purge();
        }
    }

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

    private OpenTracingService getOpenTracing() {
        OpenTracingService openTracingService = openTracingServiceProvider.get();
        if (openTracingService == null) {
            _logger.log(Level.INFO, "Error retrieving OpenTracing "
                    + "service during initialisation of "
                    + "JavaEETransactionManagerSimplified - NullPointerException");
        }
        return openTracingService;
    }

    private RequestTracingService getRequestTracing() {
        RequestTracingService requestTracingService = requestTracing.get();
        if (requestTracingService == null) {
            _logger.log(Level.INFO, "Error retrieving Request Tracing "
                    + "service during initialisation of "
                    + "JavaEETransactionManagerSimplified - NullPointerException");
        }
        return requestTracingService;
    }

    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".equalsIgnoreCase(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 /
                    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
     */
    @Override
    public void clearThreadTx() {
        setCurrentTransaction(null);
        delegates.set(null);
    }

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

    /** {@inheritDoc}
    */
    @Override
    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.
     */
    @Override
    public boolean isNullTransaction() {
        return getDelegate().isNullTransaction();
    }

    @Override
    public void shutdown() {
        if (statisticsMonitoringFuture != null) {
            statisticsMonitoringFuture.cancel(false);
        }
        if (purgeScheduledTransactionsFuture != null) {
            purgeScheduledTransactionsFuture.cancel(false);
        }
        scheduledTransactionManagerExecutor.shutdown();
    }

    @Override
    public void initRecovery(boolean force) {
        getDelegate().initRecovery(force);
    }

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

    @Override
    public boolean enlistResource(Transaction tran, TransactionalResource h)
            throws RollbackException, IllegalStateException, SystemException {
       if(_logger.isLoggable(Level.FINE)) {
           _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.enlistResource, h="
                   + h + " h.xares=" + h.getXAResource()
                   /** +" h.alloc=" +h.getResourceAllocator() **/ +" tran=" + tran);
       }

        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;

       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());
               if(_logger.isLoggable(Level.FINE)) {
                   _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.enlistResource, isSameRM? " + isSameRM);
               }
           } 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 **/
            }
        }
    }

    @Override
    public void unregisterComponentResource(TransactionalResource h) {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.unregisterComponentResource, h="
                   + h + " h.xares=" + h.getXAResource());
        }

        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
     */
    @Override
    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(_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.getResourceList, "
                    + ((rh == null)? "" : (" ResourceHandler type: "  + rh.getClass().getName()))
                    + " ResourceHandler: "  + rh);
        }

        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;
    }

    @Override
    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(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);
        }
    }

    @Override
    public boolean delistResource(Transaction tran, TransactionalResource h, int flag)
            throws IllegalStateException, SystemException {
        if(_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.delistResource, h="
                   + h + " h.xares=" + h.getXAResource() + " tran=" + tran);
        }

        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),ex);
            }
            return true;
        } else {
            return delistJTSResource(tran, h, flag);
        }
    }

    @Override
    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);
        }
    }


    @Override
    public void registerComponentResource(TransactionalResource h) {
        ComponentInvocation inv = invMgr.getCurrentInvocation();
        if (inv != null) {
            Object instance = inv.getInstance();
            if (instance == null) {
                return;
            }
            h.setComponentInstance(instance);
            List resourceList = getResourceList(instance, inv);
            if(_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.registerComponentResource, h=" + h
                    + " h.xares=" + h.getXAResource());
            }
            resourceList.add(h);
        }
    }

    private JavaEETransactionImpl initJavaEETransaction(int timeout) {
        JavaEETransactionImpl tx;
        // Do not need to use injection.
        if (timeout > 0) {
            tx = new JavaEETransactionImpl(timeout, this);
            ScheduledFuture scheduledFuture = scheduledTransactionManagerExecutor.schedule(tx, timeout, TimeUnit.SECONDS);
            tx.setScheduledTimeoutFuture(scheduledFuture);
            scheduledTransactionTimeouts.incrementAndGet();
        } else {
            tx = new JavaEETransactionImpl(this);
        }

        setCurrentTransaction(tx);

        if (openTracingServiceProvider != null) {
            OpenTracingService openTracingService = getOpenTracing();
            if (openTracingService != null && openTracingService.isEnabled()) {
                addJtaEventTraceLog(constructJTABeginSpanLog(tx), tx, openTracingService);
            }
        }
        return tx;
    }

    @Override
    public List getExistingResourceList(Object instance, ComponentInvocation inv) {
       if (inv == null) {
        return null;
    }
        List l = null;
        ResourceHandler rh = inv.getResourceHandler();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.getExistingResourceList, "
                    + ((rh == null)? "" : (" ResourceHandler type: "  + rh.getClass().getName()))
                    + " ResourceHandler: "  + rh);
        }

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

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

    }

    @Override
    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()) {
            // do not worry about re-enlisting previous invocation resources
            // if transaction is being completed
            enlistComponentResources(prev);
        }

    }

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

    @Override
    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());
        }
    }

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

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

    @Override
    public boolean isTimedOut() {
        JavaEETransaction tx = transactions.get();
        return tx == null ? false : tx.isTimedOut();
    }

    /**
     * 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.
     */
    @Override
    public void checkTransactionImport() {
        // First check if this is a local call
        int[] count = localCallCounter.get();
        if ( count != null && count[0] > 0 ) {
            count[0]--;
        } 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
     */
    @Override
    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 = localCallCounter.get();
            if ( count == null ) {
                count = new int[1];
                localCallCounter.set(count);
            }
            count[0]++;
            return;
        }

        JavaEETransaction tx = transactions.get();
        if (tx == null || !tx.isLocalTx()) {
            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 ( Exception exception ) {
            throw new RuntimeException(sm.getString("enterprise_distributedtx.unable_tostart_JTSTransaction"), exception);
        }
    }

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

    /**
     * Release a transaction. This call causes the calling thread to be
     * dissociated from the specified transaction. 

* This is used by importing transactions via the Connector contract. * * @param xid the Xid object representing a transaction. */ @Override 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.

* This is used by importing transactions via the Connector contract. * * @param xid the Xid object representing a transaction. */ @Override public void recreate(Xid xid, long timeout) throws WorkException { getDelegate().recreate(xid, timeout); } /****************************************************************************/ /** Implementations of JTA TransactionManager APIs **************************/ /****************************************************************************/ @Override 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) @Override 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. **/ @Override 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 } @Override 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); } } } if (openTracingServiceProvider != null) { OpenTracingService openTracingService = getOpenTracing(); if (openTracingService != null && openTracingService.isEnabled()) { addJtaEventTraceLog(constructJTAEndSpanLog(tx), tx, openTracingService); } } } finally { setCurrentTransaction(null); // clear current thread's tx delegates.set(null); if(acquiredlock){ getDelegate().getReadLock().unlock(); // XXX releaseReadLock(); } } // END IASRI 4662745 } @Override 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); } } } if (openTracingServiceProvider != null) { OpenTracingService openTracingService = getOpenTracing(); if (openTracingService != null && openTracingService.isEnabled()) { addJtaEventTraceLog(constructJTAEndSpanLog(tx), tx, openTracingService); } } } finally { setCurrentTransaction(null); // clear current thread's tx delegates.set(null); if(acquiredlock){ getDelegate().getReadLock().unlock(); // XXX releaseReadLock(); } } } @Override public int getStatus() throws SystemException { return getDelegate().getStatus(); } @Override 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 **/ } @Override 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 } } @Override 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 **/ } @Override 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. * *

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 * */ @Override 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. */ @Override public void setPurgeCancelledTtransactionsAfter(int num) { purgeCancelledTtransactions = num; } /** * Returns the value to be used to purge transaction tasks after the * specified number of cancelled tasks. */ @Override public int getPurgeCancelledTtransactionsAfter() { return purgeCancelledTtransactions; } @Override public JavaEETransaction getCurrentTransaction() { return transactions.get(); } @Override public void setCurrentTransaction(JavaEETransaction t) { transactions.set(t); } @Override public XAResourceWrapper getXAResourceWrapper(String clName) { return getDelegate().getXAResourceWrapper(clName); } @Override public void handlePropertyUpdate(String name, Object value) { delegate.handlePropertyUpdate(name, value); // XXX Check if the current delegate needs to be called as well. } @Override 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. */ @Override 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. */ @Override public synchronized void unfreeze(){ getDelegate().releaseWriteLock(); monitor.freezeEvent(false); } /** XXX ??? */ @Override public boolean isFrozen() { return getDelegate().isWriteLocked(); } @Override public void cleanTxnTimeout() { txnTmout.set(null); } public int getEffectiveTimeout() { Integer tmout = txnTmout.get(); if (tmout == null) { return transactionTimeout; } else { return tmout; } } @Override public void setDefaultTransactionTimeout(int seconds) { transactionTimeout = seconds < 0 ? 0 : 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 */ @Override public ArrayList getActiveTransactions() { ArrayList tranBeans = new ArrayList<>(); txnTable = new ConcurrentHashMap<>(); Transaction[] activeCopy = activeTransactions.toArray(new Transaction[0]); // get the clone of the active transactions for (Transaction tran : activeCopy) { try { 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 jakarta.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(); List 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 */ @Override 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"); } txnTable.get(txnId).setRollbackOnly(); } } @Override 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(); } } } } // Mods: Adding method for statistic dumps using TimerTask private void registerStatisticMonitorTask() { Runnable 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 } statisticsMonitoringFuture = scheduledTransactionManagerExecutor.scheduleAtFixedRate(task, 0, statInterval, TimeUnit.MILLISECONDS); } // Mods: Adding TimerTask class for statistic dumps class StatisticMonitorTask implements Runnable { @Override 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, entry.getKey() + ": " + entry.getValue()); } } } } /****************************************************************************/ /************************* Helper Methods ***********************************/ /****************************************************************************/ public static String getStatusAsString(int status) { return 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.isEmpty()) { 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, "\n\nIn JavaEETransactionManagerSimplified.enlistXAResource, h=" + h + " h.xares=" + h.getXAResource() + " tran=" + tran); } if (resourceEnlistable(h)) { if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.enlistXAResource - enlistable"); } XAResource res = h.getXAResource(); boolean result = tran.enlistResource(res); if (!h.isEnlisted()) { if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.enlistXAResource - enlist"); } } 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){ if (_logger.isLoggable(Level.FINE)) { _logger.log(Level.WARNING, "enterprise_distributedtx.pooling_excep", 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 */ 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, "\n\nIn JavaEETransactionManagerSimplified.delistJTSResource, h=" + h + " h.xares=" + h.getXAResource() + " tran=" + tran + " flag=" + flag); } if (!h.isShareable() || multipleEnlistDelists) { if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.delistJTSResource " + "- !h.isShareable() || multipleEnlistDelists"); } if (h.isTransactional() && h.isEnlisted()) { if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "\n\nIn JavaEETransactionManagerSimplified.delistJTSResource - delist"); } 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.getAllServices(JavaEETransactionManagerDelegate.class)) { setDelegate(d); } if (delegate != null && _logger.isLoggable(Level.FINE)) { _logger.log(Level.INFO, "enterprise_used_delegate_name", delegate.getClass().getName()); } } @Override 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; } private void addJtaEventTraceLog(RequestTraceSpanLog spanLog, JavaEETransaction tx, OpenTracingService openTracingService) { Tracer tracer = openTracingService.getTracer(openTracingService.getApplicationName(invMgr)); if (tracer != null) { Span span = tracer.activeSpan(); if (span != null) { span.log(spanLog.getTimeMillis(), spanLog.getLogEntries()); // Add transaction ID as baggage item if (tx != null) { if (tx.getClass().equals(JavaEETransactionImpl.class)) { span.setBaggageItem("TX-ID", ((JavaEETransactionImpl) tx).getTransactionId()); } else { span.setBaggageItem("TransactionInfo", tx.toString()); } } } } else { // If we couldn't get a tracer here, it's because we couldn't get a name from the invocation manager. // In such a case, just try to add the span log to the currently active thread local request trace getRequestTracing().addSpanLog(spanLog); } } private RequestTraceSpanLog constructJTABeginSpanLog(JavaEETransactionImpl transaction) { RequestTraceSpanLog spanLog = new RequestTraceSpanLog("jtaContextBeginEvent"); spanLog.addLogEntry("Transaction ID", transaction.getTransactionId()); spanLog.addLogEntry("Remaining Timeout", Integer.toString(transaction.getRemainingTimeout())); return spanLog; } private RequestTraceSpanLog constructJTAEndSpanLog(JavaEETransaction transaction) throws SystemException { RequestTraceSpanLog spanLog = new RequestTraceSpanLog("jtaContextEndEvent"); if (transaction.getClass().equals(JavaEETransactionImpl.class)) { JavaEETransactionImpl tx = (JavaEETransactionImpl) transaction; spanLog.addLogEntry("Transaction ID", (tx.getTransactionId())); } // Check if transaction was rolled back or committed int status = transaction.getStatus(); switch (status) { case 3: spanLog.addLogEntry("Status", "Committed"); break; case 4: spanLog.addLogEntry("Status", "Rolled Back"); break; default: spanLog.addLogEntry("Status", Integer.toString(status)); break; } return spanLog; } /****************************************************************************/ /** Implementation of jakarta.transaction.Synchronization *********************/ /****************************************************************************/ private static class JTSSynchronization implements Synchronization { private final TransactionInternal jtsTx; private final JavaEETransactionManagerSimplified javaEETM; JTSSynchronization(TransactionInternal jtsTx, JavaEETransactionManagerSimplified javaEETM){ this.jtsTx = jtsTx; this.javaEETM = javaEETM; } @Override public void beforeCompletion() {} @Override public void afterCompletion(int status) { javaEETM.remove(jtsTx); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy