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

com.sun.enterprise.resource.pool.PoolManagerImpl Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * 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.resource.pool;

import com.sun.appserv.connectors.internal.api.ConnectorConstants.PoolType;
import com.sun.appserv.connectors.internal.api.ConnectorRuntime;
import com.sun.appserv.connectors.internal.api.PoolingException;
import com.sun.appserv.connectors.internal.spi.MCFLifecycleListener;
import com.sun.enterprise.connectors.ConnectorConnectionPool;
import com.sun.enterprise.connectors.ConnectorRegistry;
import com.sun.enterprise.deployment.ResourceReferenceDescriptor;
import com.sun.enterprise.resource.ClientSecurityInfo;
import com.sun.enterprise.resource.ResourceHandle;
import com.sun.enterprise.resource.ResourceSpec;
import com.sun.enterprise.resource.allocator.ResourceAllocator;
import com.sun.enterprise.resource.listener.PoolLifeCycle;
import com.sun.enterprise.resource.rm.*;
import com.sun.enterprise.transaction.api.JavaEETransaction;
import com.sun.enterprise.transaction.api.JavaEETransactionManager;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.logging.LogDomains;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.ComponentInvocationHandler;
import org.glassfish.api.invocation.InvocationException;
import org.glassfish.resourcebase.resources.api.PoolInfo;
import org.jvnet.hk2.annotations.Service;

import jakarta.inject.Inject;
import jakarta.inject.Provider;
import jakarta.resource.ResourceException;
import jakarta.resource.spi.ManagedConnection;
import jakarta.resource.spi.ManagedConnectionFactory;
import jakarta.resource.spi.RetryableUnavailableException;
import jakarta.transaction.Synchronization;
import jakarta.transaction.Transaction;
import javax.transaction.xa.XAResource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Tony Ng, Aditya Gore
 */
@Service
public class PoolManagerImpl extends AbstractPoolManager implements ComponentInvocationHandler {

    private final ConcurrentHashMap poolTable;
    protected final static StringManager localStrings =
            StringManager.getManager(PoolManagerImpl.class);

    private ResourceManager resourceManager;
    private ResourceManager sysResourceManager;
    private ResourceManager noTxResourceManager;
    private LazyEnlistableResourceManagerImpl lazyEnlistableResourceManager;

    private static Logger _logger = null;

    @Inject
    private Provider connectorRuntimeProvider;

    private ConnectorRuntime runtime;

    static {
        _logger = LogDomains.getLogger(PoolManagerImpl.class, LogDomains.RSR_LOGGER);
    }
    private PoolLifeCycle listener;

    public PoolManagerImpl() {
        this.poolTable = new ConcurrentHashMap();
        resourceManager = new ResourceManagerImpl();
        sysResourceManager = new SystemResourceManagerImpl();
        noTxResourceManager = new NoTxResourceManagerImpl();
        lazyEnlistableResourceManager = new LazyEnlistableResourceManagerImpl();
    }

    public void createEmptyConnectionPool(PoolInfo poolInfo,
                                          PoolType pt, Hashtable env) throws PoolingException {
        //Create and initialise the connection pool
        createAndInitPool(poolInfo, pt, env);
        if (listener != null) {
            try {
               listener.poolCreated(poolInfo);
            } catch (Exception ex) {
                if(_logger.isLoggable(Level.FINE)) {
	            _logger.log(Level.FINE, "Exception thrown on pool listener");
                }
            }
        }
        //notify mcf-create
        ManagedConnectionFactory mcf = ConnectorRegistry.getInstance().getManagedConnectionFactory(poolInfo);
        if(mcf != null){
            if(mcf instanceof MCFLifecycleListener){
                ((MCFLifecycleListener)mcf).mcfCreated();
            }
        }
    }

    /**
     * Create and initialize pool if not created already.
     *
     * @param poolInfo Name of the pool to be created
     * @param pt       - PoolType
     * @return ResourcePool - newly created pool
     * @throws PoolingException when unable to create/initialize pool
     */
    private ResourcePool createAndInitPool(final PoolInfo poolInfo, PoolType pt, Hashtable env)
            throws PoolingException {
        ResourcePool pool = getPool(poolInfo);
        if (pool == null) {
            pool = ResourcePoolFactoryImpl.newInstance(poolInfo, pt, env);
            addPool(pool);
            if (_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, "Created connection  pool  and added it to PoolManager :" + pool);
            }
        }
        return pool;
    }


    // invoked by DataSource objects to obtain a connection
    public Object getResource(ResourceSpec spec, ResourceAllocator alloc, ClientSecurityInfo info)
            throws PoolingException, RetryableUnavailableException {

        Transaction tran = null;
        boolean transactional = alloc.isTransactional();

        if (transactional) {
            tran = getResourceManager(spec).getTransaction();
        }

        ResourceHandle handle =
                getResourceFromPool(spec, alloc, info, tran);

        if (!handle.supportsLazyAssociation()) {
            spec.setLazyAssociatable(false);
        }

        if (spec.isLazyAssociatable() &&
                spec.getConnectionToAssociate() != null) {
            //If getConnectionToAssociate returns a connection that means
            //we need to associate a new connection with it
            try {
                Object connection = spec.getConnectionToAssociate();
                ManagedConnection dmc
                        = (ManagedConnection) handle.getResource();
                dmc.associateConnection(connection);
            } catch (ResourceException e) {
                putbackDirectToPool(handle, spec.getPoolInfo());
                PoolingException pe = new PoolingException(
                        e.getMessage());
                pe.initCause(e);
                throw pe;
            }
        }

        //If the ResourceAdapter does not support lazy enlistment
        //we cannot either
        if (!handle.supportsLazyEnlistment()) {
            spec.setLazyEnlistable(false);
        }

        handle.setResourceSpec(spec);

        try {
            if (handle.getResourceState().isUnenlisted()) {
                //The spec being used here is the spec with the updated
                //lazy enlistment info
                //Here's the real place where we care about the correct 
                //resource manager (which in turn depends upon the ResourceSpec)
                //and that's because if lazy enlistment needs to be done
                //we need to get the LazyEnlistableResourceManager
                getResourceManager(spec).enlistResource(handle);
            }
        } catch (Exception e) {
            //In the rare cases where enlistResource throws exception, we
            //should throw the resource away
            putbackBadResourceToPool(handle);
            _logger.log(Level.WARNING, "poolmgr.err_enlisting_res_in_getconn",
                    spec.getPoolInfo());
            logFine("rm.enlistResource threw Exception. Evicting resource from pool");
            //and rethrow the exception
            throw new PoolingException(e);
        }

        return handle.getUserConnection();
    }

    public void putbackDirectToPool(ResourceHandle h, PoolInfo poolInfo) {
        // notify pool
        if (poolInfo != null) {
            ResourcePool pool = poolTable.get(poolInfo);
            if (pool != null) {
                pool.resourceClosed(h);
            }
        }
    }

    public ResourceHandle getResourceFromPool(ResourceSpec spec, ResourceAllocator alloc, ClientSecurityInfo info,
                                              Transaction tran) throws PoolingException, RetryableUnavailableException {
        ResourcePool pool = getPool(spec.getPoolInfo());
        // pool.getResource() has been modified to:
        //      - be able to create new resource if needed
        //      - block the caller until a resource is acquired or
        //              the max-wait-time expires
        return pool.getResource(spec, alloc, tran);
    }

    /**
     * Switch on matching in the pool.
     *
     * @param poolInfo Name of the pool
     */
    public boolean switchOnMatching(PoolInfo poolInfo) {
        ResourcePool pool = getPool(poolInfo);

        if (pool != null) {
            pool.switchOnMatching();
            return true;
        } else {
            return false;
        }
    }


/*    private ConcurrentHashMap getPoolTable() {
        return poolTable;
    }
*/

    private void addPool(ResourcePool pool) {
        if (_logger.isLoggable(Level.FINE)) {
            _logger.fine("Adding pool " + pool.getPoolInfo() + "to pooltable");
        }
        poolTable.put(pool.getPoolStatus().getPoolInfo(), pool);
    }


    private ResourceManager getResourceManager(ResourceSpec spec) {
        if (spec.isNonTx()) {
            logFine("Returning noTxResourceManager");
            return noTxResourceManager;
        } else if (spec.isPM()) {
            logFine("Returning sysResourceManager");
            return sysResourceManager;
        } else if (spec.isLazyEnlistable()) {
            logFine("Returning LazyEnlistableResourceManager");
            return lazyEnlistableResourceManager;
        } else {
            logFine("Returning resourceManager");
            return resourceManager;
        }
    }

    private void addSyncListener(Transaction tran) {
        Synchronization sync = new SynchronizationListener(tran);
        try {
            tran.registerSynchronization(sync);
        } catch (Exception ex) {
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("Error adding syncListener : "
                        + (ex.getMessage() != null ? ex.getMessage() : " "));
            }
        }
    }

    // called by EJB Transaction Manager
    public void transactionCompleted(Transaction tran, int status)
            throws IllegalStateException {

        Iterator iter = ((JavaEETransaction) tran).getAllParticipatingPools().iterator();
        while (iter.hasNext()) {
            ResourcePool pool = getPool((PoolInfo) iter.next());
            if (_logger.isLoggable(Level.FINE)) {
                _logger.fine("calling transactionCompleted on " + pool.getPoolInfo());
            }
            pool.transactionCompleted(tran, status);
        }
    }

    public void resourceEnlisted(Transaction tran, com.sun.appserv.connectors.internal.api.ResourceHandle h)
            throws IllegalStateException {
        ResourceHandle res = (ResourceHandle) h;

        PoolInfo poolInfo = res.getResourceSpec().getPoolInfo();
        try {
            JavaEETransaction j2eeTran = (JavaEETransaction) tran;
            if (poolInfo != null && j2eeTran.getResources(poolInfo) == null) {
                addSyncListener(tran);
            }
        } catch (ClassCastException e) {
            addSyncListener(tran);
        }
        if (poolInfo != null) {
            ResourcePool pool = getPool(poolInfo);
            if (pool != null) {
                pool.resourceEnlisted(tran, res);
            }
        }
    }

    /**
     * This method gets called by the LazyEnlistableConnectionManagerImpl when
     * a connection needs enlistment, i.e on use of a Statement etc.
     */
    public void lazyEnlist(ManagedConnection mc) throws ResourceException {
        lazyEnlistableResourceManager.lazyEnlist(mc);
    }


    private ConnectorRuntime getConnectorRuntime() {
        if(runtime == null){
            runtime = connectorRuntimeProvider.get();
        }
        return runtime;
    }

    public void registerResource(com.sun.appserv.connectors.internal.api.ResourceHandle handle) throws PoolingException {
        ResourceHandle h = (ResourceHandle)handle;
        ResourceManager rm = getResourceManager(h.getResourceSpec());
        rm.registerResource(h);
    }

    public void registerPoolLifeCycleListener(PoolLifeCycle poolListener) {
        listener = poolListener;
    }

    public void unregisterPoolLifeCycleListener() {
        listener = null;
    }
    
    public void unregisterResource(com.sun.appserv.connectors.internal.api.ResourceHandle resource, int xaresFlag) {
        ResourceHandle h = (ResourceHandle)resource;
        ResourceManager rm = getResourceManager(h.getResourceSpec());
        rm.unregisterResource(h, xaresFlag);
    }

    public void resourceClosed(ResourceHandle resource) {
        ResourceManager rm = getResourceManager(resource.getResourceSpec());
        rm.delistResource(resource, XAResource.TMSUCCESS);
        putbackResourceToPool(resource, false);
    }

    public void badResourceClosed(ResourceHandle resource) {
        ResourceManager rm = getResourceManager(resource.getResourceSpec());
        rm.delistResource(resource, XAResource.TMSUCCESS);
        putbackBadResourceToPool(resource);
    }

    public void resourceErrorOccurred(ResourceHandle resource) {
        putbackResourceToPool(resource, true);
    }

    public void resourceAbortOccurred(ResourceHandle resource) {
        ResourceManager rm = getResourceManager(resource.getResourceSpec());
        rm.delistResource(resource, XAResource.TMSUCCESS);
        putbackResourceToPool(resource, true);
    }

    public void putbackBadResourceToPool(ResourceHandle h) {

        // notify pool
        PoolInfo poolInfo = h.getResourceSpec().getPoolInfo();
        if (poolInfo != null) {
            ResourcePool pool = poolTable.get(poolInfo);
            if (pool != null) {
                synchronized (pool) {
                    pool.resourceClosed(h);
                    h.setConnectionErrorOccurred();
                    pool.resourceErrorOccurred(h);
                }
            }
        }
    }

    public void putbackResourceToPool(ResourceHandle h,
                                      boolean errorOccurred) {

        // notify pool
        PoolInfo poolInfo = h.getResourceSpec().getPoolInfo();
        if (poolInfo != null) {
            ResourcePool pool = poolTable.get(poolInfo);
            if (pool != null) {
                if (errorOccurred) {
                    pool.resourceErrorOccurred(h);
                } else {
                    pool.resourceClosed(h);
                }
            }
        }
    }


    /**
     * Use this method if the string being passed does not 
* involve multiple concatenations
* Avoid using this method in exception-catch blocks as they * are not frequently executed
* * @param msg String */ private void logFine(String msg) { if (_logger.isLoggable(Level.FINE)) { _logger.fine(msg); } } public ResourcePool getPool(PoolInfo poolInfo) { if (poolInfo == null) { return null; } return poolTable.get(poolInfo); } /** * Kill the pool with the specified pool name * * @param poolInfo - The name of the pool to kill */ public void killPool(PoolInfo poolInfo) { //empty the pool //and remove from poolTable ResourcePool pool = poolTable.get(poolInfo); if (pool != null) { pool.cancelResizerTask(); pool.emptyPool(); if (_logger.isLoggable(Level.FINE)) { _logger.fine("Removing pool " + pool + " from pooltable"); } poolTable.remove(poolInfo); if (listener != null){ listener.poolDestroyed(poolInfo); } //notify mcf-destroy ManagedConnectionFactory mcf = ConnectorRegistry.getInstance().getManagedConnectionFactory(poolInfo); if(mcf != null){ if(mcf instanceof MCFLifecycleListener){ ((MCFLifecycleListener)mcf).mcfDestroyed(); } } } } public void killFreeConnectionsInPools() { Iterator pools = poolTable.values().iterator(); logFine("Killing all free connections in pools"); while (pools.hasNext()) { ResourcePool pool = (ResourcePool) pools.next(); if (pool != null) { PoolInfo poolInfo = pool.getPoolStatus().getPoolInfo(); try { if (poolInfo != null) { ResourcePool poolToKill = poolTable.get(poolInfo); if (poolToKill != null) { pool.emptyFreeConnectionsInPool(); } if (_logger.isLoggable(Level.FINE)){ _logger.fine("Now killing free connections in pool : " + poolInfo); } } } catch (Exception e) { if (_logger.isLoggable(Level.FINE)) { _logger.fine("Error killing pool : " + poolInfo + " :: " + (e.getMessage() != null ? e.getMessage() : " ")); } } } } } public ResourceReferenceDescriptor getResourceReference(String jndiName, String logicalName) { Set descriptors = getConnectorRuntime().getResourceReferenceDescriptor(); List matchingRefs = new ArrayList(); if (descriptors != null) { for (Object descriptor : descriptors) { ResourceReferenceDescriptor ref = (ResourceReferenceDescriptor) descriptor; String name = ref.getJndiName(); if (jndiName.equals(name)) { matchingRefs.add(ref); } } } if(matchingRefs.size()==1){ return (ResourceReferenceDescriptor)matchingRefs.get(0); }else if(matchingRefs.size() > 1){ Iterator it = matchingRefs.iterator(); while(it.hasNext()){ ResourceReferenceDescriptor rrd = (ResourceReferenceDescriptor)it.next(); String refName = rrd.getName(); if(refName != null && logicalName != null){ refName = getJavaName(refName); if(refName.equals(getJavaName(logicalName))){ return rrd; } } } } return null; } private static String getJavaName(String name){ if(name == null || name.startsWith("java:")){ return name; }else { //by default, scope is "comp" return "java:comp/env/" + name; } } public void beforePreInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation newInv) throws InvocationException { //no-op } public void afterPreInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation curInv) throws InvocationException { //no-op } public void beforePostInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation curInv) throws InvocationException { //no-op } /* * Called by the InvocationManager at methodEnd. This method * will disassociate ManagedConnection instances from Connection * handles if the ResourceAdapter supports that. */ public void afterPostInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation curInv) throws InvocationException { postInvoke(curInv); } private void postInvoke(ComponentInvocation curInv){ ComponentInvocation invToUse = curInv; /* if(invToUse == null){ invToUse = getConnectorRuntime().getInvocationManager().getCurrentInvocation(); } */ if (invToUse == null) { return; } Object comp = invToUse.getInstance(); if (comp == null) { return; } handleLazilyAssociatedConnectionPools(comp, invToUse); } /** * If the connections associated with the component are lazily-associatable, dissociate them. * @param comp Component that acquired connections * @param invToUse component invocation */ private void handleLazilyAssociatedConnectionPools(Object comp, ComponentInvocation invToUse) { JavaEETransactionManager tm = getConnectorRuntime().getTransactionManager(); List list = tm.getExistingResourceList(comp, invToUse); if (list == null) { //For invocations of asadmin the ComponentInvocation does not //have any resources and hence the existingResourcesList is null return; } if (list.isEmpty()) return; ResourceHandle[] handles = new ResourceHandle[list.size()]; handles = (ResourceHandle[]) list.toArray(handles); for (ResourceHandle h : handles) { if (h == null) { _logger.log(Level.WARNING, "lazy_association.lazy_association_resource_handle"); continue; } ResourceSpec spec = h.getResourceSpec(); if (spec == null) { _logger.log(Level.WARNING, "lazy_association.lazy_association_resource_spec"); continue; } if (spec.isLazyAssociatable()) { //In this case we are assured that the managedConnection is //of type DissociatableManagedConnection if (h.getResource() != null) { jakarta.resource.spi.DissociatableManagedConnection mc = (jakarta.resource.spi.DissociatableManagedConnection) h.getResource(); if (h.isEnlisted()) { getResourceManager(spec).delistResource( h, XAResource.TMSUCCESS); } try { mc.dissociateConnections(); } catch (ResourceException re) { InvocationException ie = new InvocationException( re.getMessage()); ie.initCause(re); throw ie; } finally { if (h.getResourceState().isBusy()) { putbackDirectToPool(h, spec.getPoolInfo()); } } } else { _logger.log(Level.WARNING, "lazy_association.lazy_association_resource"); } } } } class SynchronizationListener implements Synchronization { private Transaction tran; SynchronizationListener(Transaction tran) { this.tran = tran; } public void afterCompletion(int status) { try { transactionCompleted(tran, status); } catch (Exception ex) { if(_logger.isLoggable(Level.FINE)) { _logger.fine("Exception in afterCompletion : " + (ex.getMessage() != null ? ex.getMessage() : " ")); } } } public void beforeCompletion() { // do nothing } } public void reconfigPoolProperties(ConnectorConnectionPool ccp) throws PoolingException { PoolInfo poolInfo = ccp.getPoolInfo(); ResourcePool pool = getPool( poolInfo ); if (pool != null ) { pool.reconfigurePool( ccp ); } } /** * Flush Connection pool by reinitializing the connections * established in the pool. * @param poolInfo * @throws com.sun.appserv.connectors.internal.api.PoolingException */ public boolean flushConnectionPool(PoolInfo poolInfo) throws PoolingException { boolean result = false; ResourcePool pool = getPool( poolInfo ); if(pool != null) { result = pool.flushConnectionPool(); } else { _logger.log(Level.WARNING, "poolmgr.flush_noop_pool_not_initialized", poolInfo); String exString = localStrings.getString("poolmgr.flush_noop_pool_not_initialized", poolInfo.toString()); throw new PoolingException(exString); } return result; } /** * Get connection pool status. * @param poolInfo * @return */ public PoolStatus getPoolStatus(PoolInfo poolInfo) { ResourcePool pool = poolTable.get(poolInfo); if(pool != null) { return pool.getPoolStatus(); } else { //TODO log exception return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy