Package com.sun.enterprise.resource.pool

Source Code of com.sun.enterprise.resource.pool.PoolManagerImpl

/*
* 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 javax.inject.Inject;
import javax.inject.Provider;
import javax.resource.ResourceException;
import javax.resource.spi.ManagedConnection;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.RetryableUnavailableException;
import javax.transaction.Synchronization;
import javax.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<PoolInfo, ResourcePool> 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<ConnectorRuntime> connectorRuntimeProvider;

    private ConnectorRuntime runtime;

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

    public PoolManagerImpl() {
        this.poolTable = new ConcurrentHashMap<PoolInfo, ResourcePool>();
        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 return the resource to the pool
            putbackDirectToPool(handle, spec.getPoolInfo());
            _logger.log(Level.WARNING, "poolmgr.err_enlisting_res_in_getconn",
                    spec.getPoolInfo());
            logFine("rm.enlistResource threw Exception. Returning resource to 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<PoolInfo, ResourcePool> 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 <br>
     * involve multiple concatenations<br>
     * Avoid using this method in exception-catch blocks as they
     * are not frequently executed <br>
     *
     * @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.size() == 0) return;

        ResourceHandle[] handles = new ResourceHandle[list.size()];
        handles = (ResourceHandle[]) list.toArray(handles);
        for (ResourceHandle h : handles) {
            ResourceSpec spec = h.getResourceSpec();
            if (spec.isLazyAssociatable()) {
                //In this case we are assured that the managedConnection is
                //of type DissociatableManagedConnection
                javax.resource.spi.DissociatableManagedConnection mc =
                        (javax.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());
                    }
                }
            }
        }
    }

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

Related Classes of com.sun.enterprise.resource.pool.PoolManagerImpl

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.