|
Glassfish example source code file (ConnectionPool.java)
The Glassfish ConnectionPool.java source code/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 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 org.glassfish.resource.common.PoolInfo; import com.sun.appserv.connectors.internal.spi.BadConnectionEventListener; import com.sun.enterprise.connectors.ConnectorConnectionPool; import com.sun.enterprise.connectors.ConnectorRuntime; import com.sun.enterprise.connectors.service.ConnectorAdminServiceUtils; import com.sun.enterprise.resource.ResourceHandle; import com.sun.enterprise.resource.ResourceSpec; import com.sun.enterprise.resource.ResourceState; import com.sun.enterprise.resource.listener.PoolLifeCycleListener; import com.sun.enterprise.resource.allocator.ResourceAllocator; import com.sun.enterprise.resource.pool.datastructure.DataStructure; import com.sun.enterprise.resource.pool.datastructure.DataStructureFactory; import com.sun.enterprise.resource.pool.resizer.Resizer; import com.sun.enterprise.resource.pool.waitqueue.PoolWaitQueue; import com.sun.enterprise.resource.pool.waitqueue.PoolWaitQueueFactory; import com.sun.enterprise.util.i18n.StringManager; import com.sun.enterprise.transaction.api.JavaEETransaction; import com.sun.logging.LogDomains; import com.sun.appserv.connectors.internal.api.PoolingException; import javax.naming.NamingException; import javax.resource.ResourceException; import javax.resource.spi.RetryableUnavailableException; import javax.transaction.Transaction; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; /** * Connection Pool for Connector & JDBC resources<br> * * @author Jagadish Ramu */ public class ConnectionPool implements ResourcePool, ConnectionLeakListener, ResourceHandler, PoolProperties { protected final static StringManager localStrings = StringManager.getManager(ConnectionPool.class); protected final static Logger _logger = LogDomains.getLogger(ConnectionPool.class,LogDomains.RSR_LOGGER); //pool life-cycle config properties protected int maxPoolSize; // Max size of the pool protected int steadyPoolSize; // Steady size of the pool protected int resizeQuantity; // used by resizer to downsize the pool protected int maxWaitTime; // The total time a thread is willing to wait for a resource object. protected long idletime; // time (in ms) before destroying a free resource //pool config properties protected boolean failAllConnections = false; protected boolean matchConnections = false; protected boolean validation = false; protected boolean preferValidateOverRecreate = false; // hold on to the resizer task so we can cancel/reschedule it. protected Resizer resizerTask; protected volatile boolean poolInitialized = false; protected Timer timer; //advanced pool config properties protected boolean connectionCreationRetry_; protected int connectionCreationRetryAttempts_; protected long conCreationRetryInterval_; protected long validateAtmostPeriodInMilliSeconds_; protected int maxConnectionUsage_; //To validate a Sun RA Pool Connection if it hasnot been validated // in the past x sec. (x=idle-timeout) //The property will be set from system property - // com.sun.enterprise.connectors.ValidateAtmostEveryIdleSecs=true private boolean validateAtmostEveryIdleSecs = false; protected String resourceSelectionStrategyClass; protected PoolLifeCycleListener poolLifeCycleListener; //Gateway used to control the concurrency within the round-trip of resource access. protected ResourceGateway gateway; protected String resourceGatewayClass; protected ConnectionLeakDetector leakDetector; protected DataStructure ds; protected String dataStructureType; protected String dataStructureParameters; protected PoolWaitQueue waitQueue; protected PoolWaitQueue reconfigWaitQueue; private long reconfigWaitTime ; protected String poolWaitQueueClass; protected final PoolInfo poolInfo; //poolName private PoolTxHelper poolTxHelper; // NOTE: This resource allocator may not be the same as the allocator passed in to getResource() protected ResourceAllocator allocator; private boolean selfManaged_; private boolean blocked = false; public ConnectionPool(PoolInfo poolInfo, Hashtable env) throws PoolingException { this.poolInfo = poolInfo; setPoolConfiguration(env); initializePoolDataStructure(); initializeResourceSelectionStrategy(); initializePoolWaitQueue(); poolTxHelper = new PoolTxHelper(this.poolInfo); gateway = ResourceGateway.getInstance(resourceGatewayClass); if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "Connection Pool : " + this.poolInfo); } } protected void initializePoolWaitQueue() throws PoolingException { waitQueue = PoolWaitQueueFactory.createPoolWaitQueue(poolWaitQueueClass); reconfigWaitQueue = PoolWaitQueueFactory.createPoolWaitQueue(poolWaitQueueClass); } protected void initializePoolDataStructure() throws PoolingException { ds = DataStructureFactory.getDataStructure(dataStructureType, dataStructureParameters, maxPoolSize, this, resourceSelectionStrategyClass); } protected void initializeResourceSelectionStrategy() { //do nothing } private void setPoolConfiguration(Hashtable env) throws PoolingException { ConnectorConnectionPool poolResource = getPoolConfigurationFromJndi(env); idletime = Integer.parseInt(poolResource.getIdleTimeoutInSeconds()) * 1000L; maxPoolSize = Integer.parseInt(poolResource.getMaxPoolSize()); steadyPoolSize = Integer.parseInt(poolResource.getSteadyPoolSize()); if (maxPoolSize < steadyPoolSize) { maxPoolSize = steadyPoolSize; } resizeQuantity = Integer.parseInt(poolResource.getPoolResizeQuantity()); maxWaitTime = Integer.parseInt(poolResource.getMaxWaitTimeInMillis()); //Make sure it's not negative. if (maxWaitTime < 0) { maxWaitTime = 0; } failAllConnections = poolResource.isFailAllConnections(); validation = poolResource.isIsConnectionValidationRequired(); validateAtmostEveryIdleSecs = poolResource.isValidateAtmostEveryIdleSecs(); dataStructureType = poolResource.getPoolDataStructureType(); dataStructureParameters = poolResource.getDataStructureParameters(); poolWaitQueueClass = poolResource.getPoolWaitQueue(); resourceSelectionStrategyClass = poolResource.getResourceSelectionStrategyClass(); resourceGatewayClass = poolResource.getResourceGatewayClass(); reconfigWaitTime = poolResource.getDynamicReconfigWaitTimeout(); setAdvancedPoolConfiguration(poolResource); } protected ConnectorConnectionPool getPoolConfigurationFromJndi(Hashtable env) throws PoolingException { ConnectorConnectionPool poolResource; try { String jndiNameOfPool = ConnectorAdminServiceUtils.getReservePrefixedJNDINameForPool(poolInfo); poolResource = (ConnectorConnectionPool) ConnectorRuntime.getRuntime().getResourceNamingService().lookup(poolInfo, jndiNameOfPool, env); } catch (NamingException ex) { throw new PoolingException(ex); } return poolResource; } // This method does not need to be synchronized since all caller methods are, // but it does not hurt. Just to be safe. protected synchronized void initPool(ResourceAllocator allocator) throws PoolingException { if (poolInitialized) { return; } this.allocator = allocator; createResources(this.allocator, steadyPoolSize - ds.getResourcesSize()); // if the idle time out is 0, then don't schedule the resizer task if (idletime > 0) { scheduleResizerTask(); } //Need to set the numConnFree of monitoring statistics to the steadyPoolSize //as monitoring might be ON during the initialization of pool. //Need not worry about the numConnUsed here as it would be initialized to //0 automatically. if(poolLifeCycleListener != null) { poolLifeCycleListener.connectionsFreed(steadyPoolSize); } poolInitialized = true; } /** * Schedules the resizer timer task. If a task is currently scheduled, * it would be canceled and a new one is scheduled. */ private void scheduleResizerTask() { if (resizerTask != null) { //cancel the current task resizerTask.cancel(); resizerTask = null; } resizerTask = initializeResizer(); if (timer == null) { timer = ConnectorRuntime.getRuntime().getTimer(); } timer.scheduleAtFixedRate(resizerTask, idletime, idletime); if (_logger.isLoggable(Level.FINEST)) { _logger.finest("scheduled resizer task"); } } protected Resizer initializeResizer() { return new Resizer(poolInfo, ds, this, this, preferValidateOverRecreate); } /** * add a resource with status busy and not enlisted * * @param alloc ResourceAllocator * @throws PoolingException when unable to add a resource */ public void addResource(ResourceAllocator alloc) throws PoolingException { int numResCreated = ds.addResource(alloc, 1); if(numResCreated > 0) { for(int i=0; i< numResCreated; i++) { if(poolLifeCycleListener != null) { poolLifeCycleListener.incrementNumConnFree(false, steadyPoolSize); } } } if (_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "Pool: resource added"); } } /** * marks resource as free. This method should be used instead of directly calling * resoureHandle.getResourceState().setBusy(false) * OR * getResourceState(resourceHandle).setBusy(false) * as this method handles stopping of connection leak tracing * If connection leak tracing is enabled, takes care of stopping * connection leak tracing * * @param resourceHandle Resource */ protected void setResourceStateToFree(ResourceHandle resourceHandle) { getResourceState(resourceHandle).setBusy(false); leakDetector.stopConnectionLeakTracing(resourceHandle, this); } /** * marks resource as busy. This method should be used instead of directly calling * resoureHandle.getResourceState().setBusy(true) * OR * getResourceState(resourceHandle).setBusy(true) * as this method handles starting of connection leak tracing * If connection leak tracing is enabled, takes care of starting * connection leak tracing * * @param resourceHandle Resource */ protected void setResourceStateToBusy(ResourceHandle resourceHandle) { getResourceState(resourceHandle).setBusy(true); leakDetector.startConnectionLeakTracing(resourceHandle, this); } /** * returns resource from the pool. * * @return a free pooled resource object matching the ResourceSpec * @throws PoolingException - if any error occurrs * - or the pool has reached its max size and the * max-connection-wait-time-in-millis has expired. */ public ResourceHandle getResource(ResourceSpec spec, ResourceAllocator alloc, Transaction txn) throws PoolingException, RetryableUnavailableException { //Note: this method should not be synchronized or the // startTime would be incorrect for threads waiting to enter /* * Here are all the comments for the method put together for * easy reference. * 1. // - Try to get a free resource. Note: internalGetResource() // will create a new resource if none is free and the max has // not been reached. // - If can't get one, get on the wait queue. // - Repeat this until maxWaitTime expires. // - If maxWaitTime == 0, repeat indefinitely. 2. //the doFailAllConnectionsProcessing method would already //have been invoked by now. //We simply go ahead and create a new resource here //from the allocator that we have and adjust the resources //list accordingly so as to not exceed the maxPoolSize ever //(i.e if steadyPoolSize == maxPoolSize ) ///Also since we are creating the resource out of the allocator //that we came into this method with, we need not worry about //matching */ ResourceHandle result = null; long startTime = System.currentTimeMillis(); long elapsedWaitTime; long remainingWaitTime = 0; while (true) { if (gateway.allowed()) { //See comment #1 above JavaEETransaction jtx = ((JavaEETransaction) txn); Set resourcesSet = null; if(jtx != null){ resourcesSet = jtx.getResources(poolInfo); } //allow when the pool is not blocked or at-least one resource is //already obtained in the current transaction. if (!blocked || (resourcesSet != null && resourcesSet.size() > 0)) { try { result = internalGetResource(spec, alloc, txn); } finally { gateway.acquiredResource(); } } } if (result != null) { // got one, return it if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionAcquired(result.getId()); elapsedWaitTime = System.currentTimeMillis() - startTime; poolLifeCycleListener.connectionRequestServed(elapsedWaitTime); if (_logger.isLoggable( Level.FINE) ) { _logger.log(Level.FINE, "Resource Pool: elapsed time " + "(ms) to get connection for [" + spec + "] : " + elapsedWaitTime); } } //got one - seems we are not doing validation or matching //return it break; } else { // did not get a resource. if (maxWaitTime > 0) { elapsedWaitTime = System.currentTimeMillis() - startTime; if (elapsedWaitTime < maxWaitTime) { // time has not expired, determine remaining wait time. remainingWaitTime = maxWaitTime - elapsedWaitTime; } else { if (!blocked) { // wait time has expired if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionTimedOut(); } String msg = localStrings.getStringWithDefault( "poolmgr.no.available.resource", "No available resource. Wait-time expired."); throw new PoolingException(msg); } } } if (!blocked) { //add to wait-queue Object waitMonitor = waitQueue.addToQueue(); if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionRequestQueued(); } synchronized (waitMonitor) { try { logFine("Resource Pool: getting on wait queue"); waitMonitor.wait(remainingWaitTime); } catch (InterruptedException ex) { //Could be system shutdown. break; } //try to remove in case that the monitor has timed // out. We dont expect the queue to grow to great numbers // so the overhead for removing inexistant objects is low. if (_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "removing wait monitor from queue: " + waitMonitor); } if (waitQueue.removeFromQueue(waitMonitor)) { if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionRequestDequeued(); } } } } else { //add to reconfig-wait-queue Object reconfigWaitMonitor = reconfigWaitQueue.addToQueue(); synchronized (reconfigWaitMonitor) { try { if(reconfigWaitTime > 0){ if(_logger.isLoggable(Level.FINEST)) { _logger.finest("[DRC] getting into reconfig wait queue for time ["+reconfigWaitTime+"]"); } reconfigWaitMonitor.wait(reconfigWaitTime); } } catch (InterruptedException ex) { //Could be system shutdown. break; } //try to remove in case that the monitor has timed // out. We don't expect the queue to grow to great numbers // so the overhead for removing inexistent objects is low. if(_logger.isLoggable(Level.FINEST)) { _logger.log(Level.FINEST, "[DRC] removing wait monitor from reconfig-wait-queue: " + reconfigWaitMonitor); } reconfigWaitQueue.removeFromQueue(reconfigWaitMonitor); if(_logger.isLoggable(Level.FINEST)) { _logger.log(Level.FINEST, "[DRC] throwing Retryable-Unavailable-Exception"); } RetryableUnavailableException rue = new RetryableUnavailableException("Pool Reconfigured, " + "Connection Factory can retry the lookup"); rue.setErrorCode(BadConnectionEventListener.POOL_RECONFIGURED_ERROR_CODE); throw rue; } } } } alloc.fillInResourceObjects(result); return result; } /** * Overridden in AssocWithThreadResourcePool to fetch the resource * cached in the ThreadLocal * In ConnectionPool this simply returns null. * * @param spec ResourceSpec * @param alloc ResourceAllocator to create a resource * @param tran Transaction * @return ResourceHandle resource from ThreadLocal */ protected ResourceHandle prefetch(ResourceSpec spec, ResourceAllocator alloc, Transaction tran) { return null; } protected ResourceHandle internalGetResource(ResourceSpec spec, ResourceAllocator alloc, Transaction tran) throws PoolingException { if (!poolInitialized) { initPool(alloc); } ResourceHandle result; result = getResourceFromTransaction(tran, alloc, spec); if(result != null){ return result; } result = prefetch(spec, alloc, tran); if (result != null) { return result; } // We didnt get a connection that is already enlisted in the current transaction (if any). result = getUnenlistedResource(spec, alloc, tran); if (result != null) { if (maxConnectionUsage_ > 0) { result.incrementUsageCount(); } if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionUsed(result.getId()); //Decrement numConnFree poolLifeCycleListener.decrementNumConnFree(); } } return result; } /** * Try to get a resource from current transaction if it is shareable<br> * @param tran Current Transaction * @param alloc ResourceAllocator * @param spec ResourceSpec * @return result ResourceHandle */ private ResourceHandle getResourceFromTransaction(Transaction tran, ResourceAllocator alloc, ResourceSpec spec) { ResourceHandle result = null; try { //comment-1: sharing is possible only if caller is marked //shareable, so abort right here if that's not the case if (tran != null && alloc.shareableWithinComponent()) { //TODO should be handled by PoolTxHelper JavaEETransaction j2eetran = (JavaEETransaction) tran; // case 1. look for free and enlisted in same tx Set set = j2eetran.getResources(poolInfo); if (set != null) { Iterator iter = set.iterator(); while (iter.hasNext()) { ResourceHandle h = (ResourceHandle) iter.next(); if (h.hasConnectionErrorOccurred()) { iter.remove(); continue; } ResourceState state = h.getResourceState(); /* * One can share a resource only for the following conditions: * 1. The caller resource is shareable (look at the outermost * if marked comment-1 * 2. The resource enlisted inside the transaction is shareable * 3. We are dealing with XA resources OR * We are dealing with a non-XA resource that's not in use * Note that sharing a non-xa resource that's in use involves * associating physical connections. * 4. The credentials of the resources match */ if (h.getResourceAllocator().shareableWithinComponent()) { if (spec.isXA() || poolTxHelper.isNonXAResourceAndFree(j2eetran, h)) { if (matchConnections) { if (!alloc.matchConnection(h)) { if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionNotMatched(); } continue; } if (h.hasConnectionErrorOccurred()) { if (failAllConnections) { //if failAllConnections has happened, we flushed the //pool, so we don't have to do iter.remove else we //will get a ConncurrentModificationException result = null; break; } iter.remove(); continue; } if (poolLifeCycleListener != null) { poolLifeCycleListener.connectionMatched(); } } if (state.isFree()) setResourceStateToBusy(h); result = h; break; } } } } } } catch (ClassCastException e) { if(_logger.isLoggable(Level.FINE)) { _logger.log(Level.FINE, "Pool: getResource : " + "transaction is not JavaEETransaction but a " + tran.getClass().getName(), e); } } return result; } /** * To provide an unenlisted, valid, matched resource from pool. * * @param spec ResourceSpec * @param alloc ResourceAllocator * @param tran Transaction * @return ResourceHandle resource from pool * @throws PoolingException Exception while getting resource from pool */ protected ResourceHandle getUnenlistedResource(ResourceSpec spec, ResourceAllocator alloc, Transaction tran) throws PoolingException { return getResourceFromPool(alloc, spec); } /** * Check whether the connection is valid * * @param h Resource to be validated * @param alloc Allocator to validate the resource * @return boolean representing validation result */ protected boolean isConnectionValid(ResourceHandle h, ResourceAllocator alloc) { boolean connectionValid = true; if (validation || validateAtmostEveryIdleSecs) { long validationPeriod; //validation period is idle timeout if validateAtmostEveryIdleSecs is set to true //else it is validateAtmostPeriodInMilliSeconds_ if (validation) validationPeriod = validateAtmostPeriodInMilliSeconds_; else validationPeriod = idletime; boolean validationRequired = true; long currentTime = h.getLastValidated(); if (validationPeriod > 0) { currentTime = System.currentTimeMillis(); long timeSinceValidation = currentTime - h.getLastValidated(); if (timeSinceValidation < validationPeriod) validationRequired = false; } if (validationRequired) { if (!alloc.isConnectionValid(h)) { connectionValid = false; incrementNumConnFailedValidation(); } else { h.setLastValidated(currentTime); } } } return connectionValid; } /** * check whether the connection retrieved from the pool matches with the request. * * @param resource Resource to be matched * @param alloc ResourceAllocator used to match the connection * @return boolean representing the match status of the connection */ protected boolean matchConnection(ResourceHandle resource, ResourceAllocator alloc) { boolean matched = true; if (matchConnections) { matched = alloc.matchConnection(resource); if (poolLifeCycleListener != null) { if (matched) { poolLifeCycleListener.connectionMatched(); } else { poolLifeCycleListener.connectionNotMatched(); } } } return matched; } /** * return resource in free list. If none is found, try to scale up the pool/purge pool and <br> * return a new resource. returns null if the pool new resources cannot be created. <br> * * @param alloc ResourceAllocator * @return ResourceHandle resource from pool * @throws PoolingException if unable to create a new resource */ protected ResourceHandle getResourceFromPool(ResourceAllocator alloc, ResourceSpec spec) throws PoolingException { // the order of serving a resource request // 1. free and enlisted in the same transaction // 2. free and unenlisted // Do NOT give out a connection that is // free and enlisted in a different transaction ResourceHandle result = null; ResourceHandle h; ArrayList<ResourceHandle> freeResources = new ArrayList Other Glassfish examples (source code examples)Here is a short list of links related to this Glassfish ConnectionPool.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.