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

org.apache.commons.pool.impl.GenericObjectPool Maven / Gradle / Ivy

There is a newer version: 20030825.183949
Show newest version
/*
 * Copyright 1999-2004 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.pool.impl;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.apache.commons.collections.CursorableLinkedList;
import org.apache.commons.pool.BaseObjectPool;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;

/**
 * A configurable {@link ObjectPool} implementation.
 * 

* When coupled with the appropriate {@link PoolableObjectFactory}, * GenericObjectPool provides robust pooling functionality for * arbitrary objects. *

* A GenericObjectPool provides a number of configurable parameters: *

    *
  • * {@link #setMaxActive maxActive} controls the maximum number of objects that can * be borrowed from the pool at one time. When non-positive, there * is no limit to the number of objects that may be active at one time. * When {@link #setMaxActive maxActive} is exceeded, the pool is said to be exhausted. *
  • *
  • * {@link #setMaxIdle maxIdle} controls the maximum number of objects that can * sit idle in the pool at any time. When negative, there * is no limit to the number of objects that may be idle at one time. *
  • *
  • * {@link #setWhenExhaustedAction whenExhaustedAction} specifies the * behaviour of the {@link #borrowObject} method when the pool is exhausted: *
      *
    • * When {@link #setWhenExhaustedAction whenExhaustedAction} is * {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject} will throw * a {@link NoSuchElementException} *
    • *
    • * When {@link #setWhenExhaustedAction whenExhaustedAction} is * {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject} will create a new * object and return it(essentially making {@link #setMaxActive maxActive} * meaningless.) *
    • *
    • * When {@link #setWhenExhaustedAction whenExhaustedAction} * is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject} will block * (invoke {@link Object#wait} until a new or idle object is available. * If a positive {@link #setMaxWait maxWait} * value is supplied, the {@link #borrowObject} will block for at * most that many milliseconds, after which a {@link NoSuchElementException} * will be thrown. If {@link #setMaxWait maxWait} is non-positive, * the {@link #borrowObject} method will block indefinitely. *
    • *
    *
  • *
  • * When {@link #setTestOnBorrow testOnBorrow} is set, the pool will * attempt to validate each object before it is returned from the * {@link #borrowObject} method. (Using the provided factory's * {@link PoolableObjectFactory#validateObject} method.) Objects that fail * to validate will be dropped from the pool, and a different object will * be borrowed. *
  • *
  • * When {@link #setTestOnReturn testOnReturn} is set, the pool will * attempt to validate each object before it is returned to the pool in the * {@link #returnObject} method. (Using the provided factory's * {@link PoolableObjectFactory#validateObject} * method.) Objects that fail to validate will be dropped from the pool. *
  • *
*

* Optionally, one may configure the pool to examine and possibly evict objects as they * sit idle in the pool. This is performed by an "idle object eviction" thread, which * runs asychronously. The idle object eviction thread may be configured using the * following attributes: *

    *
  • * {@link #setTimeBetweenEvictionRunsMillis timeBetweenEvictionRunsMillis} * indicates how long the eviction thread should sleep before "runs" of examining * idle objects. When non-positive, no eviction thread will be launched. *
  • *
  • * {@link #setMinEvictableIdleTimeMillis minEvictableIdleTimeMillis} * specifies the minimum amount of time that an object may sit idle in the pool * before it is eligable for eviction due to idle time. When non-positive, no object * will be dropped from the pool due to idle time alone. *
  • *
  • * {@link #setTestWhileIdle testWhileIdle} indicates whether or not idle * objects should be validated using the factory's * {@link PoolableObjectFactory#validateObject} method. Objects * that fail to validate will be dropped from the pool. *
  • *
*

* GenericObjectPool is not usable without a {@link PoolableObjectFactory}. A * non-null factory must be provided either as a constructor argument * or via a call to {@link #setFactory} before the pool is used. * * @see GenericKeyedObjectPool * @author Rodney Waldhoff * @author Dirk Verbeeck * @version $Revision: 1.32 $ $Date: 2004/04/27 20:15:56 $ */ public class GenericObjectPool extends BaseObjectPool implements ObjectPool { //--- public constants ------------------------------------------- /** * A "when exhausted action" type indicating that when the pool is * exhausted (i.e., the maximum number of active objects has * been reached), the {@link #borrowObject} * method should fail, throwing a {@link NoSuchElementException}. * @see #WHEN_EXHAUSTED_BLOCK * @see #WHEN_EXHAUSTED_GROW * @see #setWhenExhaustedAction */ public static final byte WHEN_EXHAUSTED_FAIL = 0; /** * A "when exhausted action" type indicating that when the pool * is exhausted (i.e., the maximum number * of active objects has been reached), the {@link #borrowObject} * method should block until a new object is available, or the * {@link #getMaxWait maximum wait time} has been reached. * @see #WHEN_EXHAUSTED_FAIL * @see #WHEN_EXHAUSTED_GROW * @see #setMaxWait * @see #getMaxWait * @see #setWhenExhaustedAction */ public static final byte WHEN_EXHAUSTED_BLOCK = 1; /** * A "when exhausted action" type indicating that when the pool is * exhausted (i.e., the maximum number * of active objects has been reached), the {@link #borrowObject} * method should simply create a new object anyway. * @see #WHEN_EXHAUSTED_FAIL * @see #WHEN_EXHAUSTED_GROW * @see #setWhenExhaustedAction */ public static final byte WHEN_EXHAUSTED_GROW = 2; /** * The default cap on the number of "sleeping" instances in the pool. * @see #getMaxIdle * @see #setMaxIdle */ public static final int DEFAULT_MAX_IDLE = 8; /** * The default minimum number of "sleeping" instances in the pool * before before the evictor thread (if active) spawns new objects. * @see #getMinIdle * @see #setMinIdle */ public static final int DEFAULT_MIN_IDLE = 0; /** * The default cap on the total number of active instances from the pool. * @see #getMaxActive */ public static final int DEFAULT_MAX_ACTIVE = 8; /** * The default "when exhausted action" for the pool. * @see #WHEN_EXHAUSTED_BLOCK * @see #WHEN_EXHAUSTED_FAIL * @see #WHEN_EXHAUSTED_GROW * @see #setWhenExhaustedAction */ public static final byte DEFAULT_WHEN_EXHAUSTED_ACTION = WHEN_EXHAUSTED_BLOCK; /** * The default maximum amount of time (in millis) the * {@link #borrowObject} method should block before throwing * an exception when the pool is exhausted and the * {@link #getWhenExhaustedAction "when exhausted" action} is * {@link #WHEN_EXHAUSTED_BLOCK}. * @see #getMaxWait * @see #setMaxWait */ public static final long DEFAULT_MAX_WAIT = -1L; /** * The default "test on borrow" value. * @see #getTestOnBorrow * @see #setTestOnBorrow */ public static final boolean DEFAULT_TEST_ON_BORROW = false; /** * The default "test on return" value. * @see #getTestOnReturn * @see #setTestOnReturn */ public static final boolean DEFAULT_TEST_ON_RETURN = false; /** * The default "test while idle" value. * @see #getTestWhileIdle * @see #setTestWhileIdle * @see #getTimeBetweenEvictionRunsMillis * @see #setTimeBetweenEvictionRunsMillis */ public static final boolean DEFAULT_TEST_WHILE_IDLE = false; /** * The default "time between eviction runs" value. * @see #getTimeBetweenEvictionRunsMillis * @see #setTimeBetweenEvictionRunsMillis */ public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L; /** * The default number of objects to examine per run in the * idle object evictor. * @see #getNumTestsPerEvictionRun * @see #setNumTestsPerEvictionRun * @see #getTimeBetweenEvictionRunsMillis * @see #setTimeBetweenEvictionRunsMillis */ public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3; /** * The default value for {@link #getMinEvictableIdleTimeMillis}. * @see #getMinEvictableIdleTimeMillis * @see #setMinEvictableIdleTimeMillis */ public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L; //--- constructors ----------------------------------------------- /** * Create a new GenericObjectPool. */ public GenericObjectPool() { this(null,DEFAULT_MAX_ACTIVE,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_MIN_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects */ public GenericObjectPool(PoolableObjectFactory factory) { this(factory,DEFAULT_MAX_ACTIVE,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_MIN_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param config a non-null {@link GenericObjectPool.Config} describing my configuration */ public GenericObjectPool(PoolableObjectFactory factory, GenericObjectPool.Config config) { this(factory,config.maxActive,config.whenExhaustedAction,config.maxWait,config.maxIdle,config.minIdle,config.testOnBorrow,config.testOnReturn,config.timeBetweenEvictionRunsMillis,config.numTestsPerEvictionRun,config.minEvictableIdleTimeMillis,config.testWhileIdle); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive) { this(factory,maxActive,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_MIN_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction}) * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait) { this(factory,maxActive,whenExhaustedAction,maxWait,DEFAULT_MAX_IDLE,DEFAULT_MIN_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction}) * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait}) * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #getTestOnBorrow}) * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #getTestOnReturn}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, boolean testOnBorrow, boolean testOnReturn) { this(factory,maxActive,whenExhaustedAction,maxWait,DEFAULT_MAX_IDLE,DEFAULT_MIN_IDLE,testOnBorrow,testOnReturn,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction}) * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait}) * @param maxIdle the maximum number of idle objects in my pool (see {@link #getMaxIdle}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle) { this(factory,maxActive,whenExhaustedAction,maxWait,maxIdle,DEFAULT_MIN_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #getWhenExhaustedAction}) * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait}) * @param maxIdle the maximum number of idle objects in my pool (see {@link #getMaxIdle}) * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #getTestOnBorrow}) * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #getTestOnReturn}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, boolean testOnBorrow, boolean testOnReturn) { this(factory,maxActive,whenExhaustedAction,maxWait,maxIdle,DEFAULT_MIN_IDLE,testOnBorrow,testOnReturn,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction}) * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait}) * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle}) * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow}) * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn}) * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis}) * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun}) * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis}) * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) { this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle); } /** * Create a new GenericObjectPool using the specified values. * @param factory the (possibly null)PoolableObjectFactory to use to create, validate and destroy objects * @param maxActive the maximum number of objects that can be borrowed from me at one time (see {@link #setMaxActive}) * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction}) * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and whenExhaustedAction is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait}) * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle}) * @param minIdle the minimum number of idle objects in my pool (see {@link #setMinIdle}) * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow}) * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn}) * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis}) * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun}) * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis}) * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle}) */ public GenericObjectPool(PoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int minIdle, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) { _factory = factory; _maxActive = maxActive; switch(whenExhaustedAction) { case WHEN_EXHAUSTED_BLOCK: case WHEN_EXHAUSTED_FAIL: case WHEN_EXHAUSTED_GROW: _whenExhaustedAction = whenExhaustedAction; break; default: throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction + " not recognized."); } _maxWait = maxWait; _maxIdle = maxIdle; _minIdle = minIdle; _testOnBorrow = testOnBorrow; _testOnReturn = testOnReturn; _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; _numTestsPerEvictionRun = numTestsPerEvictionRun; _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; _testWhileIdle = testWhileIdle; _pool = new CursorableLinkedList(); startEvictor(_timeBetweenEvictionRunsMillis); } //--- public methods --------------------------------------------- //--- configuration methods -------------------------------------- /** * Returns the cap on the total number of active instances from my pool. * @return the cap on the total number of active instances from my pool. * @see #setMaxActive */ public synchronized int getMaxActive() { return _maxActive; } /** * Sets the cap on the total number of active instances from my pool. * @param maxActive The cap on the total number of active instances from my pool. * Use a negative value for an infinite number of instances. * @see #getMaxActive */ public synchronized void setMaxActive(int maxActive) { _maxActive = maxActive; notifyAll(); } /** * Returns the action to take when the {@link #borrowObject} method * is invoked when the pool is exhausted (the maximum number * of "active" objects has been reached). * * @return one of {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL} or {@link #WHEN_EXHAUSTED_GROW} * @see #setWhenExhaustedAction */ public synchronized byte getWhenExhaustedAction() { return _whenExhaustedAction; } /** * Sets the action to take when the {@link #borrowObject} method * is invoked when the pool is exhausted (the maximum number * of "active" objects has been reached). * * @param whenExhaustedAction the action code, which must be one of * {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL}, * or {@link #WHEN_EXHAUSTED_GROW} * @see #getWhenExhaustedAction */ public synchronized void setWhenExhaustedAction(byte whenExhaustedAction) { switch(whenExhaustedAction) { case WHEN_EXHAUSTED_BLOCK: case WHEN_EXHAUSTED_FAIL: case WHEN_EXHAUSTED_GROW: _whenExhaustedAction = whenExhaustedAction; notifyAll(); break; default: throw new IllegalArgumentException("whenExhaustedAction " + whenExhaustedAction + " not recognized."); } } /** * Returns the maximum amount of time (in milliseconds) the * {@link #borrowObject} method should block before throwing * an exception when the pool is exhausted and the * {@link #setWhenExhaustedAction "when exhausted" action} is * {@link #WHEN_EXHAUSTED_BLOCK}. * * When less than 0, the {@link #borrowObject} method * may block indefinitely. * * @see #setMaxWait * @see #setWhenExhaustedAction * @see #WHEN_EXHAUSTED_BLOCK */ public synchronized long getMaxWait() { return _maxWait; } /** * Sets the maximum amount of time (in milliseconds) the * {@link #borrowObject} method should block before throwing * an exception when the pool is exhausted and the * {@link #setWhenExhaustedAction "when exhausted" action} is * {@link #WHEN_EXHAUSTED_BLOCK}. * * When less than 0, the {@link #borrowObject} method * may block indefinitely. * * @see #getMaxWait * @see #setWhenExhaustedAction * @see #WHEN_EXHAUSTED_BLOCK */ public synchronized void setMaxWait(long maxWait) { _maxWait = maxWait; notifyAll(); } /** * Returns the cap on the number of "idle" instances in the pool. * @return the cap on the number of "idle" instances in the pool. * @see #setMaxIdle */ public synchronized int getMaxIdle() { return _maxIdle; } /** * Sets the cap on the number of "idle" instances in the pool. * @param maxIdle The cap on the number of "idle" instances in the pool. * Use a negative value to indicate an unlimited number * of idle instances. * @see #getMaxIdle */ public synchronized void setMaxIdle(int maxIdle) { _maxIdle = maxIdle; notifyAll(); } /** * Sets the minimum number of objects allowed in the pool * before the evictor thread (if active) spawns new objects. * (Note no objects are created when: numActive + numIdle >= maxActive) * * @param minIdle The minimum number of objects. * @see #getMinIdle */ public synchronized void setMinIdle(int minIdle) { _minIdle = minIdle; notifyAll(); } /** * Returns the minimum number of objects allowed in the pool * before the evictor thread (if active) spawns new objects. * (Note no objects are created when: numActive + numIdle >= maxActive) * * @return The minimum number of objects. * @see #setMinIdle */ public synchronized int getMinIdle() { return _minIdle; } /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * before being returned by the {@link #borrowObject} * method. If the object fails to validate, * it will be dropped from the pool, and we will attempt * to borrow another. * * @see #setTestOnBorrow */ public synchronized boolean getTestOnBorrow() { return _testOnBorrow; } /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * before being returned by the {@link #borrowObject} * method. If the object fails to validate, * it will be dropped from the pool, and we will attempt * to borrow another. * * @see #getTestOnBorrow */ public synchronized void setTestOnBorrow(boolean testOnBorrow) { _testOnBorrow = testOnBorrow; } /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * before being returned to the pool within the * {@link #returnObject}. * * @see #setTestOnReturn */ public synchronized boolean getTestOnReturn() { return _testOnReturn; } /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * before being returned to the pool within the * {@link #returnObject}. * * @see #getTestOnReturn */ public synchronized void setTestOnReturn(boolean testOnReturn) { _testOnReturn = testOnReturn; } /** * Returns the number of milliseconds to sleep between runs of the * idle object evictor thread. * When non-positive, no idle object evictor thread will be * run. * * @see #setTimeBetweenEvictionRunsMillis */ public synchronized long getTimeBetweenEvictionRunsMillis() { return _timeBetweenEvictionRunsMillis; } /** * Sets the number of milliseconds to sleep between runs of the * idle object evictor thread. * When non-positive, no idle object evictor thread will be * run. * * @see #getTimeBetweenEvictionRunsMillis */ public synchronized void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) { _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; startEvictor(_timeBetweenEvictionRunsMillis); } /** * Returns the number of objects to examine during each run of the * idle object evictor thread (if any). * * @see #setNumTestsPerEvictionRun * @see #setTimeBetweenEvictionRunsMillis */ public synchronized int getNumTestsPerEvictionRun() { return _numTestsPerEvictionRun; } /** * Sets the number of objects to examine during each run of the * idle object evictor thread (if any). *

* When a negative value is supplied, ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun}) * tests will be run. I.e., when the value is -n, roughly one nth of the * idle objects will be tested per run. * * @see #getNumTestsPerEvictionRun * @see #setTimeBetweenEvictionRunsMillis */ public synchronized void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) { _numTestsPerEvictionRun = numTestsPerEvictionRun; } /** * Returns the minimum amount of time an object may sit idle in the pool * before it is eligable for eviction by the idle object evictor * (if any). * * @see #setMinEvictableIdleTimeMillis * @see #setTimeBetweenEvictionRunsMillis */ public synchronized long getMinEvictableIdleTimeMillis() { return _minEvictableIdleTimeMillis; } /** * Sets the minimum amount of time an object may sit idle in the pool * before it is eligable for eviction by the idle object evictor * (if any). * When non-positive, no objects will be evicted from the pool * due to idle time alone. * * @see #getMinEvictableIdleTimeMillis * @see #setTimeBetweenEvictionRunsMillis */ public synchronized void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) { _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * by the idle object evictor (if any). If an object * fails to validate, it will be dropped from the pool. * * @see #setTestWhileIdle * @see #setTimeBetweenEvictionRunsMillis */ public synchronized boolean getTestWhileIdle() { return _testWhileIdle; } /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * by the idle object evictor (if any). If an object * fails to validate, it will be dropped from the pool. * * @see #getTestWhileIdle * @see #setTimeBetweenEvictionRunsMillis */ public synchronized void setTestWhileIdle(boolean testWhileIdle) { _testWhileIdle = testWhileIdle; } /** * Sets my configuration. * @see GenericObjectPool.Config */ public synchronized void setConfig(GenericObjectPool.Config conf) { setMaxIdle(conf.maxIdle); setMinIdle(conf.minIdle); setMaxActive(conf.maxActive); setMaxWait(conf.maxWait); setWhenExhaustedAction(conf.whenExhaustedAction); setTestOnBorrow(conf.testOnBorrow); setTestOnReturn(conf.testOnReturn); setTestWhileIdle(conf.testWhileIdle); setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun); setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis); setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis); notifyAll(); } //-- ObjectPool methods ------------------------------------------ public Object borrowObject() throws Exception { long starttime = System.currentTimeMillis(); boolean newlyCreated = false; for(;;) { ObjectTimestampPair pair = null; synchronized(this) { assertOpen(); // if there are any sleeping, just grab one of those try { pair = (ObjectTimestampPair)(_pool.removeFirst()); } catch(NoSuchElementException e) { ; /* ignored */ } // otherwise if(null == pair) { // check if we can create one // (note we know that the num sleeping is 0, else we wouldn't be here) if(_maxActive <= 0 || _numActive < _maxActive) { // allow new object to be created } else { // the pool is exhausted switch(_whenExhaustedAction) { case WHEN_EXHAUSTED_GROW: // allow new object to be created break; case WHEN_EXHAUSTED_FAIL: throw new NoSuchElementException(); case WHEN_EXHAUSTED_BLOCK: try { if(_maxWait <= 0) { wait(); } else { wait(_maxWait); } } catch(InterruptedException e) { // ignored } if(_maxWait > 0 && ((System.currentTimeMillis() - starttime) >= _maxWait)) { throw new NoSuchElementException("Timeout waiting for idle object"); } else { continue; // keep looping } default: throw new IllegalArgumentException("whenExhaustedAction " + _whenExhaustedAction + " not recognized."); } } } _numActive++; } // end synchronized // create new object when needed if(null == pair) { try { Object obj = _factory.makeObject(); pair = new ObjectTimestampPair(obj); newlyCreated = true; } catch (Exception e) { // object cannot be created synchronized(this) { _numActive--; notifyAll(); } throw e; } } // activate & validate the object try { _factory.activateObject(pair.value); if(_testOnBorrow && !_factory.validateObject(pair.value)) { throw new Exception("validateObject failed"); } return pair.value; } catch (Exception e) { // object cannot be activated or is invalid synchronized(this) { _numActive--; notifyAll(); } try { _factory.destroyObject(pair.value); } catch (Exception e2) { // cannot destroy broken object } if(newlyCreated) { throw new NoSuchElementException("Could not create a validated object, cause: " + e.getMessage()); } else { continue; // keep looping } } } } public void invalidateObject(Object obj) throws Exception { assertOpen(); try { _factory.destroyObject(obj); } finally { synchronized(this) { _numActive--; notifyAll(); // _numActive has changed } } } public synchronized void clear() { assertOpen(); for(Iterator it = _pool.iterator(); it.hasNext(); ) { try { _factory.destroyObject(((ObjectTimestampPair)(it.next())).value); } catch(Exception e) { // ignore error, keep destroying the rest } it.remove(); } _pool.clear(); notifyAll(); // num sleeping has changed } public synchronized int getNumActive() { assertOpen(); return _numActive; } public synchronized int getNumIdle() { assertOpen(); return _pool.size(); } public void returnObject(Object obj) throws Exception { assertOpen(); addObjectToPool(obj, true); } private void addObjectToPool(Object obj, boolean decrementNumActive) throws Exception { boolean success = true; if(_testOnReturn && !(_factory.validateObject(obj))) { success = false; } else { try { _factory.passivateObject(obj); } catch(Exception e) { success = false; } } boolean shouldDestroy = !success; synchronized(this) { if (decrementNumActive) { _numActive--; } if((_maxIdle >= 0) && (_pool.size() >= _maxIdle)) { shouldDestroy = true; } else if(success) { _pool.addFirst(new ObjectTimestampPair(obj)); } notifyAll(); // _numActive has changed } if(shouldDestroy) { try { _factory.destroyObject(obj); } catch(Exception e) { // ignored } } } public synchronized void close() throws Exception { clear(); _pool = null; _factory = null; if(null != _evictionCursor) { _evictionCursor.close(); _evictionCursor = null; } startEvictor(-1L); super.close(); } public synchronized void setFactory(PoolableObjectFactory factory) throws IllegalStateException { assertOpen(); if(0 < getNumActive()) { throw new IllegalStateException("Objects are already active"); } else { clear(); _factory = factory; } } public synchronized void evict() throws Exception { assertOpen(); if(!_pool.isEmpty()) { if(null == _evictionCursor) { _evictionCursor = (_pool.cursor(_pool.size())); } else if(!_evictionCursor.hasPrevious()) { _evictionCursor.close(); _evictionCursor = (_pool.cursor(_pool.size())); } for(int i=0,m=getNumTests();i 0 && System.currentTimeMillis() - pair.tstamp > _minEvictableIdleTimeMillis) { removeObject = true; } else if(_testWhileIdle) { boolean active = false; try { _factory.activateObject(pair.value); active = true; } catch(Exception e) { removeObject=true; } if(active) { if(!_factory.validateObject(pair.value)) { removeObject=true; } else { try { _factory.passivateObject(pair.value); } catch(Exception e) { removeObject=true; } } } } if(removeObject) { try { _evictionCursor.remove(); _factory.destroyObject(pair.value); } catch(Exception e) { ; // ignored } } } } } // if !empty } /** * Check to see if we are below our minimum number of objects * if so enough to bring us back to our minimum. */ private void ensureMinIdle() throws Exception { // this method isn't synchronized so the // calculateDeficit is done at the beginning // as a loop limit and a second time inside the loop // to stop when another thread already returned the // needed objects int objectDeficit = calculateDeficit(); for ( int j = 0 ; j < objectDeficit && calculateDeficit() > 0 ; j++ ) { addObject(); } } private synchronized int calculateDeficit() { int objectDeficit = getMinIdle() - getNumIdle(); if (_maxActive > 0) { int growLimit = Math.max(0, getMaxActive() - getNumActive() - getNumIdle()); objectDeficit = Math.min(objectDeficit, growLimit); } return objectDeficit; } /** * Create an object, and place it into the pool. * addObject() is useful for "pre-loading" a pool with idle objects. */ public void addObject() throws Exception { Object obj = _factory.makeObject(); addObjectToPool(obj, false); } //--- non-public methods ---------------------------------------- /** * Start the eviction thread or service, or when * delay is non-positive, stop it * if it is already running. */ protected synchronized void startEvictor(long delay) { if(null != _evictor) { _evictor.cancel(); _evictor = null; } if(delay > 0) { _evictor = new Evictor(delay); Thread t = new Thread(_evictor); t.setDaemon(true); t.start(); } } synchronized String debugInfo() { StringBuffer buf = new StringBuffer(); buf.append("Active: ").append(getNumActive()).append("\n"); buf.append("Idle: ").append(getNumIdle()).append("\n"); buf.append("Idle Objects:\n"); Iterator it = _pool.iterator(); long time = System.currentTimeMillis(); while(it.hasNext()) { ObjectTimestampPair pair = (ObjectTimestampPair)(it.next()); buf.append("\t").append(pair.value).append("\t").append(time - pair.tstamp).append("\n"); } return buf.toString(); } private int getNumTests() { if(_numTestsPerEvictionRun >= 0) { return _numTestsPerEvictionRun; } else { return(int)(Math.ceil((double)_pool.size()/Math.abs((double)_numTestsPerEvictionRun))); } } //--- inner classes ---------------------------------------------- /** * A simple "struct" encapsulating an object instance and a timestamp. */ class ObjectTimestampPair { Object value; long tstamp; ObjectTimestampPair(Object val) { this(val,System.currentTimeMillis()); } ObjectTimestampPair(Object val, long time) { value = val; tstamp = time; } } /** * The idle object evictor thread. * @see #setTimeBetweenEvictionRunsMillis */ class Evictor implements Runnable { private boolean _cancelled = false; private long _delay = 0L; public Evictor(long delay) { _delay = delay; } void cancel() { _cancelled = true; } public void run() { while(!_cancelled) { try { Thread.sleep(_delay); } catch(Exception e) { // ignored } try { evict(); } catch(Exception e) { // ignored } try { ensureMinIdle(); } catch(Exception e) { // ignored } } synchronized(GenericObjectPool.this) { if(null != _evictionCursor) { _evictionCursor.close(); _evictionCursor = null; } } } } /** * A simple "struct" encapsulating the * configuration information for a {@link GenericObjectPool}. * @see GenericObjectPool#GenericObjectPool(org.apache.commons.pool.PoolableObjectFactory,org.apache.commons.pool.impl.GenericObjectPool.Config) * @see GenericObjectPool#setConfig */ public static class Config { public int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE; public int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE; public int maxActive = GenericObjectPool.DEFAULT_MAX_ACTIVE; public long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT; public byte whenExhaustedAction = GenericObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION; public boolean testOnBorrow = GenericObjectPool.DEFAULT_TEST_ON_BORROW; public boolean testOnReturn = GenericObjectPool.DEFAULT_TEST_ON_RETURN; public boolean testWhileIdle = GenericObjectPool.DEFAULT_TEST_WHILE_IDLE; public long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; public int numTestsPerEvictionRun = GenericObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN; public long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; } //--- private attributes --------------------------------------- /** * The cap on the number of idle instances in the pool. * @see #setMaxIdle * @see #getMaxIdle */ private int _maxIdle = DEFAULT_MAX_IDLE; /** * The cap on the minimum number of idle instances in the pool. * @see #setMinIdle * @see #getMinIdle */ private int _minIdle = DEFAULT_MIN_IDLE; /** * The cap on the total number of active instances from the pool. * @see #setMaxActive * @see #getMaxActive */ private int _maxActive = DEFAULT_MAX_ACTIVE; /** * The maximum amount of time (in millis) the * {@link #borrowObject} method should block before throwing * an exception when the pool is exhausted and the * {@link #getWhenExhaustedAction "when exhausted" action} is * {@link #WHEN_EXHAUSTED_BLOCK}. * * When less than 0, the {@link #borrowObject} method * may block indefinitely. * * @see #setMaxWait * @see #getMaxWait * @see #WHEN_EXHAUSTED_BLOCK * @see #setWhenExhaustedAction * @see #getWhenExhaustedAction */ private long _maxWait = DEFAULT_MAX_WAIT; /** * The action to take when the {@link #borrowObject} method * is invoked when the pool is exhausted (the maximum number * of "active" objects has been reached). * * @see #WHEN_EXHAUSTED_BLOCK * @see #WHEN_EXHAUSTED_FAIL * @see #WHEN_EXHAUSTED_GROW * @see #DEFAULT_WHEN_EXHAUSTED_ACTION * @see #setWhenExhaustedAction * @see #getWhenExhaustedAction */ private byte _whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION; /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * before being returned by the {@link #borrowObject} * method. If the object fails to validate, * it will be dropped from the pool, and we will attempt * to borrow another. * * @see #setTestOnBorrow * @see #getTestOnBorrow */ private boolean _testOnBorrow = DEFAULT_TEST_ON_BORROW; /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * before being returned to the pool within the * {@link #returnObject}. * * @see #getTestOnReturn * @see #setTestOnReturn */ private boolean _testOnReturn = DEFAULT_TEST_ON_RETURN; /** * When true, objects will be * {@link PoolableObjectFactory#validateObject validated} * by the idle object evictor (if any). If an object * fails to validate, it will be dropped from the pool. * * @see #setTestWhileIdle * @see #getTestWhileIdle * @see #getTimeBetweenEvictionRunsMillis * @see #setTimeBetweenEvictionRunsMillis */ private boolean _testWhileIdle = DEFAULT_TEST_WHILE_IDLE; /** * The number of milliseconds to sleep between runs of the * idle object evictor thread. * When non-positive, no idle object evictor thread will be * run. * * @see #setTimeBetweenEvictionRunsMillis * @see #getTimeBetweenEvictionRunsMillis */ private long _timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS; /** * The number of objects to examine during each run of the * idle object evictor thread (if any). *

* When a negative value is supplied, ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun}) * tests will be run. I.e., when the value is -n, roughly one nth of the * idle objects will be tested per run. * * @see #setNumTestsPerEvictionRun * @see #getNumTestsPerEvictionRun * @see #getTimeBetweenEvictionRunsMillis * @see #setTimeBetweenEvictionRunsMillis */ private int _numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN; /** * The minimum amount of time an object may sit idle in the pool * before it is eligable for eviction by the idle object evictor * (if any). * When non-positive, no objects will be evicted from the pool * due to idle time alone. * * @see #setMinEvictableIdleTimeMillis * @see #getMinEvictableIdleTimeMillis * @see #getTimeBetweenEvictionRunsMillis * @see #setTimeBetweenEvictionRunsMillis */ private long _minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS; /** My pool. */ private CursorableLinkedList _pool = null; /** My {@link PoolableObjectFactory}. */ private PoolableObjectFactory _factory = null; /** * The number of objects {@link #borrowObject} borrowed * from the pool, but not yet returned. */ private int _numActive = 0; /** * My idle object eviction thread, if any. */ private Evictor _evictor = null; private CursorableLinkedList.Cursor _evictionCursor = null; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy