0001: /*
0002: * Copyright 1999-2004,2006 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016:
0017: package org.apache.commons.pool.impl;
0018:
0019: import java.util.HashMap;
0020: import java.util.Iterator;
0021: import java.util.ListIterator;
0022: import java.util.Map;
0023: import java.util.NoSuchElementException;
0024: import java.util.Set;
0025: import java.util.TreeMap;
0026: import java.util.LinkedList;
0027: import java.util.HashSet;
0028: import java.util.TimerTask;
0029:
0030: import org.apache.commons.pool.BaseKeyedObjectPool;
0031: import org.apache.commons.pool.KeyedObjectPool;
0032: import org.apache.commons.pool.KeyedPoolableObjectFactory;
0033:
0034: /**
0035: * A configurable {@link KeyedObjectPool} implementation.
0036: * <p>
0037: * When coupled with the appropriate {@link KeyedPoolableObjectFactory},
0038: * <tt>GenericKeyedObjectPool</tt> provides robust pooling functionality for
0039: * arbitrary objects.
0040: * <p>
0041: * A <tt>GenericKeyedObjectPool</tt> provides a number of configurable parameters:
0042: * <ul>
0043: * <li>
0044: * {@link #setMaxActive <i>maxActive</i>} controls the maximum number of objects (per key)
0045: * that can be borrowed from the pool at one time. When non-positive, there
0046: * is no limit to the number of objects that may be active at one time.
0047: * When {@link #setMaxActive <i>maxActive</i>} is exceeded, the pool is said to be exhausted.
0048: * </li>
0049: * <li>
0050: * {@link #setMaxIdle <i>maxIdle</i>} controls the maximum number of objects that can
0051: * sit idle in the pool (per key) at any time. When negative, there
0052: * is no limit to the number of objects that may be idle at one time.
0053: * </li>
0054: * <li>
0055: * {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} specifies the
0056: * behaviour of the {@link #borrowObject} method when the pool is exhausted:
0057: * <ul>
0058: * <li>
0059: * When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} is
0060: * {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject} will throw
0061: * a {@link NoSuchElementException}
0062: * </li>
0063: * <li>
0064: * When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} is
0065: * {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject} will create a new
0066: * object and return it(essentially making {@link #setMaxActive <i>maxActive</i>}
0067: * meaningless.)
0068: * </li>
0069: * <li>
0070: * When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>}
0071: * is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject} will block
0072: * (invoke {@link Object#wait} until a new or idle object is available.
0073: * If a positive {@link #setMaxWait <i>maxWait</i>}
0074: * value is supplied, the {@link #borrowObject} will block for at
0075: * most that many milliseconds, after which a {@link NoSuchElementException}
0076: * will be thrown. If {@link #setMaxWait <i>maxWait</i>} is non-positive,
0077: * the {@link #borrowObject} method will block indefinitely.
0078: * </li>
0079: * </ul>
0080: * </li>
0081: * <li>
0082: * When {@link #setTestOnBorrow <i>testOnBorrow</i>} is set, the pool will
0083: * attempt to validate each object before it is returned from the
0084: * {@link #borrowObject} method. (Using the provided factory's
0085: * {@link KeyedPoolableObjectFactory#validateObject} method.) Objects that fail
0086: * to validate will be dropped from the pool, and a different object will
0087: * be borrowed.
0088: * </li>
0089: * <li>
0090: * When {@link #setTestOnReturn <i>testOnReturn</i>} is set, the pool will
0091: * attempt to validate each object before it is returned to the pool in the
0092: * {@link #returnObject} method. (Using the provided factory's
0093: * {@link KeyedPoolableObjectFactory#validateObject}
0094: * method.) Objects that fail to validate will be dropped from the pool.
0095: * </li>
0096: * </ul>
0097: * <p>
0098: * Optionally, one may configure the pool to examine and possibly evict objects as they
0099: * sit idle in the pool. This is performed by an "idle object eviction" thread, which
0100: * runs asychronously. The idle object eviction thread may be configured using the
0101: * following attributes:
0102: * <ul>
0103: * <li>
0104: * {@link #setTimeBetweenEvictionRunsMillis <i>timeBetweenEvictionRunsMillis</i>}
0105: * indicates how long the eviction thread should sleep before "runs" of examining
0106: * idle objects. When non-positive, no eviction thread will be launched.
0107: * </li>
0108: * <li>
0109: * {@link #setMinEvictableIdleTimeMillis <i>minEvictableIdleTimeMillis</i>}
0110: * specifies the minimum amount of time that an object may sit idle in the pool
0111: * before it is eligable for eviction due to idle time. When non-positive, no object
0112: * will be dropped from the pool due to idle time alone.
0113: * </li>
0114: * <li>
0115: * {@link #setTestWhileIdle <i>testWhileIdle</i>} indicates whether or not idle
0116: * objects should be validated using the factory's
0117: * {@link KeyedPoolableObjectFactory#validateObject} method. Objects
0118: * that fail to validate will be dropped from the pool.
0119: * </li>
0120: * </ul>
0121: * <p>
0122: * GenericKeyedObjectPool is not usable without a {@link KeyedPoolableObjectFactory}. A
0123: * non-<code>null</code> factory must be provided either as a constructor argument
0124: * or via a call to {@link #setFactory} before the pool is used.
0125: * </p>
0126: * @see GenericObjectPool
0127: * @author Rodney Waldhoff
0128: * @author Dirk Verbeeck
0129: * @version $Revision: 386116 $ $Date: 2006-03-15 12:15:58 -0500 (Wed, 15 Mar 2006) $
0130: */
0131: public class GenericKeyedObjectPool extends BaseKeyedObjectPool
0132: implements KeyedObjectPool {
0133:
0134: //--- public constants -------------------------------------------
0135:
0136: /**
0137: * A "when exhausted action" type indicating that when the pool is
0138: * exhausted (i.e., the maximum number of active objects has
0139: * been reached), the {@link #borrowObject}
0140: * method should fail, throwing a {@link NoSuchElementException}.
0141: * @see #WHEN_EXHAUSTED_BLOCK
0142: * @see #WHEN_EXHAUSTED_GROW
0143: * @see #setWhenExhaustedAction
0144: */
0145: public static final byte WHEN_EXHAUSTED_FAIL = 0;
0146:
0147: /**
0148: * A "when exhausted action" type indicating that when the pool
0149: * is exhausted (i.e., the maximum number
0150: * of active objects has been reached), the {@link #borrowObject}
0151: * method should block until a new object is available, or the
0152: * {@link #getMaxWait maximum wait time} has been reached.
0153: * @see #WHEN_EXHAUSTED_FAIL
0154: * @see #WHEN_EXHAUSTED_GROW
0155: * @see #setMaxWait
0156: * @see #getMaxWait
0157: * @see #setWhenExhaustedAction
0158: */
0159: public static final byte WHEN_EXHAUSTED_BLOCK = 1;
0160:
0161: /**
0162: * A "when exhausted action" type indicating that when the pool is
0163: * exhausted (i.e., the maximum number
0164: * of active objects has been reached), the {@link #borrowObject}
0165: * method should simply create a new object anyway.
0166: * @see #WHEN_EXHAUSTED_FAIL
0167: * @see #WHEN_EXHAUSTED_GROW
0168: * @see #setWhenExhaustedAction
0169: */
0170: public static final byte WHEN_EXHAUSTED_GROW = 2;
0171:
0172: /**
0173: * The default cap on the number of idle instances in the pool
0174: * (per key).
0175: * @see #getMaxIdle
0176: * @see #setMaxIdle
0177: */
0178: public static final int DEFAULT_MAX_IDLE = 8;
0179:
0180: /**
0181: * The default cap on the total number of active instances from the pool
0182: * (per key).
0183: * @see #getMaxActive
0184: * @see #setMaxActive
0185: */
0186: public static final int DEFAULT_MAX_ACTIVE = 8;
0187:
0188: /**
0189: * The default cap on the the maximum number of objects that can exists at one time.
0190: * @see #getMaxTotal
0191: * @see #setMaxTotal
0192: */
0193: public static final int DEFAULT_MAX_TOTAL = -1;
0194:
0195: /**
0196: * The default "when exhausted action" for the pool.
0197: * @see #WHEN_EXHAUSTED_BLOCK
0198: * @see #WHEN_EXHAUSTED_FAIL
0199: * @see #WHEN_EXHAUSTED_GROW
0200: * @see #setWhenExhaustedAction
0201: */
0202: public static final byte DEFAULT_WHEN_EXHAUSTED_ACTION = WHEN_EXHAUSTED_BLOCK;
0203:
0204: /**
0205: * The default maximum amount of time (in millis) the
0206: * {@link #borrowObject} method should block before throwing
0207: * an exception when the pool is exhausted and the
0208: * {@link #getWhenExhaustedAction "when exhausted" action} is
0209: * {@link #WHEN_EXHAUSTED_BLOCK}.
0210: * @see #getMaxWait
0211: * @see #setMaxWait
0212: */
0213: public static final long DEFAULT_MAX_WAIT = -1L;
0214:
0215: /**
0216: * The default "test on borrow" value.
0217: * @see #getTestOnBorrow
0218: * @see #setTestOnBorrow
0219: */
0220: public static final boolean DEFAULT_TEST_ON_BORROW = false;
0221:
0222: /**
0223: * The default "test on return" value.
0224: * @see #getTestOnReturn
0225: * @see #setTestOnReturn
0226: */
0227: public static final boolean DEFAULT_TEST_ON_RETURN = false;
0228:
0229: /**
0230: * The default "test while idle" value.
0231: * @see #getTestWhileIdle
0232: * @see #setTestWhileIdle
0233: * @see #getTimeBetweenEvictionRunsMillis
0234: * @see #setTimeBetweenEvictionRunsMillis
0235: */
0236: public static final boolean DEFAULT_TEST_WHILE_IDLE = false;
0237:
0238: /**
0239: * The default "time between eviction runs" value.
0240: * @see #getTimeBetweenEvictionRunsMillis
0241: * @see #setTimeBetweenEvictionRunsMillis
0242: */
0243: public static final long DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS = -1L;
0244:
0245: /**
0246: * The default number of objects to examine per run in the
0247: * idle object evictor.
0248: * @see #getNumTestsPerEvictionRun
0249: * @see #setNumTestsPerEvictionRun
0250: * @see #getTimeBetweenEvictionRunsMillis
0251: * @see #setTimeBetweenEvictionRunsMillis
0252: */
0253: public static final int DEFAULT_NUM_TESTS_PER_EVICTION_RUN = 3;
0254:
0255: /**
0256: * The default value for {@link #getMinEvictableIdleTimeMillis}.
0257: * @see #getMinEvictableIdleTimeMillis
0258: * @see #setMinEvictableIdleTimeMillis
0259: */
0260: public static final long DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS = 1000L * 60L * 30L;
0261:
0262: /**
0263: * The default minimum level of idle objects in the pool.
0264: * @see #setMinIdle
0265: * @see #getMinIdle
0266: */
0267: public static final int DEFAULT_MIN_IDLE = 0;
0268:
0269: //--- constructors -----------------------------------------------
0270:
0271: /**
0272: * Create a new <tt>GenericKeyedObjectPool</tt>..
0273: */
0274: public GenericKeyedObjectPool() {
0275: this (null, DEFAULT_MAX_ACTIVE, DEFAULT_WHEN_EXHAUSTED_ACTION,
0276: DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
0277: DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN,
0278: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0279: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0280: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0281: DEFAULT_TEST_WHILE_IDLE);
0282: }
0283:
0284: /**
0285: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0286: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0287: */
0288: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory) {
0289: this (factory, DEFAULT_MAX_ACTIVE,
0290: DEFAULT_WHEN_EXHAUSTED_ACTION, DEFAULT_MAX_WAIT,
0291: DEFAULT_MAX_IDLE, DEFAULT_TEST_ON_BORROW,
0292: DEFAULT_TEST_ON_RETURN,
0293: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0294: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0295: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0296: DEFAULT_TEST_WHILE_IDLE);
0297: }
0298:
0299: /**
0300: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0301: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0302: * @param config a non-<tt>null</tt> {@link GenericKeyedObjectPool.Config} describing my configuration
0303: */
0304: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0305: GenericKeyedObjectPool.Config config) {
0306: this (factory, config.maxActive, config.whenExhaustedAction,
0307: config.maxWait, config.maxIdle, config.maxTotal,
0308: config.testOnBorrow, config.testOnReturn,
0309: config.timeBetweenEvictionRunsMillis,
0310: config.numTestsPerEvictionRun,
0311: config.minEvictableIdleTimeMillis, config.testWhileIdle);
0312: }
0313:
0314: /**
0315: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0316: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0317: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0318: */
0319: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0320: int maxActive) {
0321: this (factory, maxActive, DEFAULT_WHEN_EXHAUSTED_ACTION,
0322: DEFAULT_MAX_WAIT, DEFAULT_MAX_IDLE,
0323: DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN,
0324: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0325: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0326: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0327: DEFAULT_TEST_WHILE_IDLE);
0328: }
0329:
0330: /**
0331: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0332: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0333: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0334: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0335: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
0336: */
0337: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0338: int maxActive, byte whenExhaustedAction, long maxWait) {
0339: this (factory, maxActive, whenExhaustedAction, maxWait,
0340: DEFAULT_MAX_IDLE, DEFAULT_TEST_ON_BORROW,
0341: DEFAULT_TEST_ON_RETURN,
0342: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0343: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0344: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0345: DEFAULT_TEST_WHILE_IDLE);
0346: }
0347:
0348: /**
0349: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0350: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0351: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0352: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
0353: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0354: * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
0355: * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
0356: */
0357: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0358: int maxActive, byte whenExhaustedAction, long maxWait,
0359: boolean testOnBorrow, boolean testOnReturn) {
0360: this (factory, maxActive, whenExhaustedAction, maxWait,
0361: DEFAULT_MAX_IDLE, testOnBorrow, testOnReturn,
0362: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0363: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0364: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0365: DEFAULT_TEST_WHILE_IDLE);
0366: }
0367:
0368: /**
0369: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0370: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0371: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0372: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0373: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
0374: * @param maxIdle the maximum number of idle objects in my pool (per key) (see {@link #setMaxIdle})
0375: */
0376: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0377: int maxActive, byte whenExhaustedAction, long maxWait,
0378: int maxIdle) {
0379: this (factory, maxActive, whenExhaustedAction, maxWait, maxIdle,
0380: DEFAULT_TEST_ON_BORROW, DEFAULT_TEST_ON_RETURN,
0381: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0382: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0383: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0384: DEFAULT_TEST_WHILE_IDLE);
0385: }
0386:
0387: /**
0388: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0389: * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
0390: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0391: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0392: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
0393: * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
0394: * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
0395: * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
0396: */
0397: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0398: int maxActive, byte whenExhaustedAction, long maxWait,
0399: int maxIdle, boolean testOnBorrow, boolean testOnReturn) {
0400: this (factory, maxActive, whenExhaustedAction, maxWait, maxIdle,
0401: testOnBorrow, testOnReturn,
0402: DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
0403: DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
0404: DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
0405: DEFAULT_TEST_WHILE_IDLE);
0406: }
0407:
0408: /**
0409: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0410: * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
0411: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0412: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0413: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
0414: * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
0415: * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
0416: * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
0417: * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
0418: * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun})
0419: * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis})
0420: * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
0421: */
0422: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0423: int maxActive, byte whenExhaustedAction, long maxWait,
0424: int maxIdle, boolean testOnBorrow, boolean testOnReturn,
0425: long timeBetweenEvictionRunsMillis,
0426: int numTestsPerEvictionRun,
0427: long minEvictableIdleTimeMillis, boolean testWhileIdle) {
0428: this (factory, maxActive, whenExhaustedAction, maxWait, maxIdle,
0429: GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, testOnBorrow,
0430: testOnReturn, timeBetweenEvictionRunsMillis,
0431: numTestsPerEvictionRun, minEvictableIdleTimeMillis,
0432: testWhileIdle);
0433: }
0434:
0435: /**
0436: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0437: * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
0438: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0439: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0440: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
0441: * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
0442: * @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
0443: * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
0444: * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
0445: * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
0446: * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun})
0447: * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis})
0448: * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
0449: */
0450: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0451: int maxActive, byte whenExhaustedAction, long maxWait,
0452: int maxIdle, int maxTotal, boolean testOnBorrow,
0453: boolean testOnReturn, long timeBetweenEvictionRunsMillis,
0454: int numTestsPerEvictionRun,
0455: long minEvictableIdleTimeMillis, boolean testWhileIdle) {
0456: this (factory, maxActive, whenExhaustedAction, maxWait, maxIdle,
0457: maxTotal, GenericKeyedObjectPool.DEFAULT_MIN_IDLE,
0458: testOnBorrow, testOnReturn,
0459: timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
0460: minEvictableIdleTimeMillis, testWhileIdle);
0461: }
0462:
0463: /**
0464: * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
0465: * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
0466: * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
0467: * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
0468: * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
0469: * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
0470: * @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
0471: * @param minIdle the minimum number of idle objects to have in the pool at any one time (see {@link #setMinIdle})
0472: * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
0473: * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
0474: * @param timeBetweenEvictionRunsMillis the amount of time (in milliseconds) to sleep between examining idle objects for eviction (see {@link #setTimeBetweenEvictionRunsMillis})
0475: * @param numTestsPerEvictionRun the number of idle objects to examine per run within the idle object eviction thread (if any) (see {@link #setNumTestsPerEvictionRun})
0476: * @param minEvictableIdleTimeMillis the minimum number of milliseconds an object can sit idle in the pool before it is eligable for evcition (see {@link #setMinEvictableIdleTimeMillis})
0477: * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
0478: */
0479: public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory,
0480: int maxActive, byte whenExhaustedAction, long maxWait,
0481: int maxIdle, int maxTotal, int minIdle,
0482: boolean testOnBorrow, boolean testOnReturn,
0483: long timeBetweenEvictionRunsMillis,
0484: int numTestsPerEvictionRun,
0485: long minEvictableIdleTimeMillis, boolean testWhileIdle) {
0486: _factory = factory;
0487: _maxActive = maxActive;
0488: switch (whenExhaustedAction) {
0489: case WHEN_EXHAUSTED_BLOCK:
0490: case WHEN_EXHAUSTED_FAIL:
0491: case WHEN_EXHAUSTED_GROW:
0492: _whenExhaustedAction = whenExhaustedAction;
0493: break;
0494: default:
0495: throw new IllegalArgumentException("whenExhaustedAction "
0496: + whenExhaustedAction + " not recognized.");
0497: }
0498: _maxWait = maxWait;
0499: _maxIdle = maxIdle;
0500: _maxTotal = maxTotal;
0501: _minIdle = minIdle;
0502: _testOnBorrow = testOnBorrow;
0503: _testOnReturn = testOnReturn;
0504: _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
0505: _numTestsPerEvictionRun = numTestsPerEvictionRun;
0506: _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
0507: _testWhileIdle = testWhileIdle;
0508:
0509: _poolMap = new HashMap();
0510: _activeMap = new HashMap();
0511:
0512: startEvictor(_timeBetweenEvictionRunsMillis);
0513: }
0514:
0515: //--- public methods ---------------------------------------------
0516:
0517: //--- configuration methods --------------------------------------
0518:
0519: /**
0520: * Returns the cap on the number of active instances from my pool (per key).
0521: * @return the cap on the number of active instances from my pool (per key).
0522: * @see #setMaxActive
0523: */
0524: public synchronized int getMaxActive() {
0525: return _maxActive;
0526: }
0527:
0528: /**
0529: * Sets the cap on the number of active instances from my pool (per key).
0530: * @param maxActive The cap on the number of active instances from my pool (per key).
0531: * Use a negative value for an infinite number of instances.
0532: * @see #getMaxActive
0533: */
0534: public synchronized void setMaxActive(int maxActive) {
0535: _maxActive = maxActive;
0536: notifyAll();
0537: }
0538:
0539: /**
0540: * Returns the cap on the total number of instances from my pool if non-positive.
0541: * @return the cap on the total number of instances from my pool if non-positive.
0542: * @see #setMaxTotal
0543: */
0544: public synchronized int getMaxTotal() {
0545: return _maxTotal;
0546: }
0547:
0548: /**
0549: * Sets the cap on the total number of instances from my pool if non-positive.
0550: * @param maxTotal The cap on the total number of instances from my pool.
0551: * Use a non-positive value for an infinite number of instances.
0552: * @see #getMaxTotal
0553: */
0554: public synchronized void setMaxTotal(int maxTotal) {
0555: _maxTotal = maxTotal;
0556: notifyAll();
0557: }
0558:
0559: /**
0560: * Returns the action to take when the {@link #borrowObject} method
0561: * is invoked when the pool is exhausted (the maximum number
0562: * of "active" objects has been reached).
0563: *
0564: * @return one of {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL} or {@link #WHEN_EXHAUSTED_GROW}
0565: * @see #setWhenExhaustedAction
0566: */
0567: public synchronized byte getWhenExhaustedAction() {
0568: return _whenExhaustedAction;
0569: }
0570:
0571: /**
0572: * Sets the action to take when the {@link #borrowObject} method
0573: * is invoked when the pool is exhausted (the maximum number
0574: * of "active" objects has been reached).
0575: *
0576: * @param whenExhaustedAction the action code, which must be one of
0577: * {@link #WHEN_EXHAUSTED_BLOCK}, {@link #WHEN_EXHAUSTED_FAIL},
0578: * or {@link #WHEN_EXHAUSTED_GROW}
0579: * @see #getWhenExhaustedAction
0580: */
0581: public synchronized void setWhenExhaustedAction(
0582: byte whenExhaustedAction) {
0583: switch (whenExhaustedAction) {
0584: case WHEN_EXHAUSTED_BLOCK:
0585: case WHEN_EXHAUSTED_FAIL:
0586: case WHEN_EXHAUSTED_GROW:
0587: _whenExhaustedAction = whenExhaustedAction;
0588: notifyAll();
0589: break;
0590: default:
0591: throw new IllegalArgumentException("whenExhaustedAction "
0592: + whenExhaustedAction + " not recognized.");
0593: }
0594: }
0595:
0596: /**
0597: * Returns the maximum amount of time (in milliseconds) the
0598: * {@link #borrowObject} method should block before throwing
0599: * an exception when the pool is exhausted and the
0600: * {@link #setWhenExhaustedAction "when exhausted" action} is
0601: * {@link #WHEN_EXHAUSTED_BLOCK}.
0602: *
0603: * When less than 0, the {@link #borrowObject} method
0604: * may block indefinitely.
0605: *
0606: * @see #setMaxWait
0607: * @see #setWhenExhaustedAction
0608: * @see #WHEN_EXHAUSTED_BLOCK
0609: */
0610: public synchronized long getMaxWait() {
0611: return _maxWait;
0612: }
0613:
0614: /**
0615: * Sets the maximum amount of time (in milliseconds) the
0616: * {@link #borrowObject} method should block before throwing
0617: * an exception when the pool is exhausted and the
0618: * {@link #setWhenExhaustedAction "when exhausted" action} is
0619: * {@link #WHEN_EXHAUSTED_BLOCK}.
0620: *
0621: * When less than 0, the {@link #borrowObject} method
0622: * may block indefinitely.
0623: *
0624: * @see #getMaxWait
0625: * @see #setWhenExhaustedAction
0626: * @see #WHEN_EXHAUSTED_BLOCK
0627: */
0628: public synchronized void setMaxWait(long maxWait) {
0629: _maxWait = maxWait;
0630: }
0631:
0632: /**
0633: * Returns the cap on the number of "idle" instances in the pool.
0634: * @return the cap on the number of "idle" instances in the pool.
0635: * @see #setMaxIdle
0636: */
0637: public synchronized int getMaxIdle() {
0638: return _maxIdle;
0639: }
0640:
0641: /**
0642: * Sets the cap on the number of "idle" instances in the pool.
0643: * @param maxIdle The cap on the number of "idle" instances in the pool.
0644: * Use a negative value to indicate an unlimited number
0645: * of idle instances.
0646: * @see #getMaxIdle
0647: */
0648: public synchronized void setMaxIdle(int maxIdle) {
0649: _maxIdle = maxIdle;
0650: notifyAll();
0651: }
0652:
0653: /**
0654: * Sets the minimum number of idle objects in pool to maintain (per key)
0655: * @param poolSize - The minimum size of the pool
0656: * @see #getMinIdle
0657: */
0658: public synchronized void setMinIdle(int poolSize) {
0659: _minIdle = poolSize;
0660: }
0661:
0662: /**
0663: * Returns the minimum number of idle objects in pool to maintain (per key)
0664: * @return the minimum number of idle objects in pool to maintain (per key)
0665: * @see #setMinIdle
0666: */
0667: public synchronized int getMinIdle() {
0668: return _minIdle;
0669: }
0670:
0671: /**
0672: * When <tt>true</tt>, objects will be
0673: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
0674: * before being returned by the {@link #borrowObject}
0675: * method. If the object fails to validate,
0676: * it will be dropped from the pool, and we will attempt
0677: * to borrow another.
0678: *
0679: * @see #setTestOnBorrow
0680: */
0681: public synchronized boolean getTestOnBorrow() {
0682: return _testOnBorrow;
0683: }
0684:
0685: /**
0686: * When <tt>true</tt>, objects will be
0687: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
0688: * before being returned by the {@link #borrowObject}
0689: * method. If the object fails to validate,
0690: * it will be dropped from the pool, and we will attempt
0691: * to borrow another.
0692: *
0693: * @see #getTestOnBorrow
0694: */
0695: public synchronized void setTestOnBorrow(boolean testOnBorrow) {
0696: _testOnBorrow = testOnBorrow;
0697: }
0698:
0699: /**
0700: * When <tt>true</tt>, objects will be
0701: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
0702: * before being returned to the pool within the
0703: * {@link #returnObject}.
0704: *
0705: * @see #setTestOnReturn
0706: */
0707: public synchronized boolean getTestOnReturn() {
0708: return _testOnReturn;
0709: }
0710:
0711: /**
0712: * When <tt>true</tt>, objects will be
0713: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
0714: * before being returned to the pool within the
0715: * {@link #returnObject}.
0716: *
0717: * @see #getTestOnReturn
0718: */
0719: public synchronized void setTestOnReturn(boolean testOnReturn) {
0720: _testOnReturn = testOnReturn;
0721: }
0722:
0723: /**
0724: * Returns the number of milliseconds to sleep between runs of the
0725: * idle object evictor thread.
0726: * When non-positive, no idle object evictor thread will be
0727: * run.
0728: *
0729: * @see #setTimeBetweenEvictionRunsMillis
0730: */
0731: public synchronized long getTimeBetweenEvictionRunsMillis() {
0732: return _timeBetweenEvictionRunsMillis;
0733: }
0734:
0735: /**
0736: * Sets the number of milliseconds to sleep between runs of the
0737: * idle object evictor thread.
0738: * When non-positive, no idle object evictor thread will be
0739: * run.
0740: *
0741: * @see #getTimeBetweenEvictionRunsMillis
0742: */
0743: public synchronized void setTimeBetweenEvictionRunsMillis(
0744: long timeBetweenEvictionRunsMillis) {
0745: _timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
0746: startEvictor(_timeBetweenEvictionRunsMillis);
0747: }
0748:
0749: /**
0750: * Returns the number of objects to examine during each run of the
0751: * idle object evictor thread (if any).
0752: *
0753: * @see #setNumTestsPerEvictionRun
0754: * @see #setTimeBetweenEvictionRunsMillis
0755: */
0756: public synchronized int getNumTestsPerEvictionRun() {
0757: return _numTestsPerEvictionRun;
0758: }
0759:
0760: /**
0761: * Sets the number of objects to examine during each run of the
0762: * idle object evictor thread (if any).
0763: * <p>
0764: * When a negative value is supplied, <tt>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</tt>
0765: * tests will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
0766: * idle objects will be tested per run.
0767: *
0768: * @see #getNumTestsPerEvictionRun
0769: * @see #setTimeBetweenEvictionRunsMillis
0770: */
0771: public synchronized void setNumTestsPerEvictionRun(
0772: int numTestsPerEvictionRun) {
0773: _numTestsPerEvictionRun = numTestsPerEvictionRun;
0774: }
0775:
0776: /**
0777: * Returns the minimum amount of time an object may sit idle in the pool
0778: * before it is eligable for eviction by the idle object evictor
0779: * (if any).
0780: *
0781: * @see #setMinEvictableIdleTimeMillis
0782: * @see #setTimeBetweenEvictionRunsMillis
0783: */
0784: public synchronized long getMinEvictableIdleTimeMillis() {
0785: return _minEvictableIdleTimeMillis;
0786: }
0787:
0788: /**
0789: * Sets the minimum amount of time an object may sit idle in the pool
0790: * before it is eligable for eviction by the idle object evictor
0791: * (if any).
0792: * When non-positive, no objects will be evicted from the pool
0793: * due to idle time alone.
0794: *
0795: * @see #getMinEvictableIdleTimeMillis
0796: * @see #setTimeBetweenEvictionRunsMillis
0797: */
0798: public synchronized void setMinEvictableIdleTimeMillis(
0799: long minEvictableIdleTimeMillis) {
0800: _minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
0801: }
0802:
0803: /**
0804: * When <tt>true</tt>, objects will be
0805: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
0806: * by the idle object evictor (if any). If an object
0807: * fails to validate, it will be dropped from the pool.
0808: *
0809: * @see #setTestWhileIdle
0810: * @see #setTimeBetweenEvictionRunsMillis
0811: */
0812: public synchronized boolean getTestWhileIdle() {
0813: return _testWhileIdle;
0814: }
0815:
0816: /**
0817: * When <tt>true</tt>, objects will be
0818: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
0819: * by the idle object evictor (if any). If an object
0820: * fails to validate, it will be dropped from the pool.
0821: *
0822: * @see #getTestWhileIdle
0823: * @see #setTimeBetweenEvictionRunsMillis
0824: */
0825: public synchronized void setTestWhileIdle(boolean testWhileIdle) {
0826: _testWhileIdle = testWhileIdle;
0827: }
0828:
0829: /**
0830: * Sets my configuration.
0831: * @see GenericKeyedObjectPool.Config
0832: */
0833: public synchronized void setConfig(
0834: GenericKeyedObjectPool.Config conf) {
0835: setMaxIdle(conf.maxIdle);
0836: setMaxActive(conf.maxActive);
0837: setMaxTotal(conf.maxTotal);
0838: setMinIdle(conf.minIdle);
0839: setMaxWait(conf.maxWait);
0840: setWhenExhaustedAction(conf.whenExhaustedAction);
0841: setTestOnBorrow(conf.testOnBorrow);
0842: setTestOnReturn(conf.testOnReturn);
0843: setTestWhileIdle(conf.testWhileIdle);
0844: setNumTestsPerEvictionRun(conf.numTestsPerEvictionRun);
0845: setMinEvictableIdleTimeMillis(conf.minEvictableIdleTimeMillis);
0846: setTimeBetweenEvictionRunsMillis(conf.timeBetweenEvictionRunsMillis);
0847: }
0848:
0849: //-- ObjectPool methods ------------------------------------------
0850:
0851: public synchronized Object borrowObject(Object key)
0852: throws Exception {
0853: long starttime = System.currentTimeMillis();
0854: boolean newlyCreated = false;
0855: for (;;) {
0856: LinkedList pool = (LinkedList) (_poolMap.get(key));
0857: if (null == pool) {
0858: pool = new LinkedList();
0859: _poolMap.put(key, pool);
0860: }
0861: ObjectTimestampPair pair = null;
0862: // if there are any sleeping, just grab one of those
0863: try {
0864: pair = (ObjectTimestampPair) (pool.removeFirst());
0865: if (null != pair) {
0866: _totalIdle--;
0867: }
0868: } catch (NoSuchElementException e) { /* ignored */
0869: }
0870: // otherwise
0871: if (null == pair) {
0872: // if there is a totalMaxActive and we are at the limit then
0873: // we have to make room
0874: if ((_maxTotal > 0)
0875: && (_totalActive + _totalIdle >= _maxTotal)) {
0876: clearOldest();
0877: }
0878:
0879: // check if we can create one
0880: // (note we know that the num sleeping is 0, else we wouldn't be here)
0881: int active = getActiveCount(key);
0882: if ((_maxActive < 0 || active < _maxActive)
0883: && (_maxTotal < 0 || _totalActive + _totalIdle < _maxTotal)) {
0884: Object obj = _factory.makeObject(key);
0885: pair = new ObjectTimestampPair(obj);
0886: newlyCreated = true;
0887: } else {
0888: // the pool is exhausted
0889: switch (_whenExhaustedAction) {
0890: case WHEN_EXHAUSTED_GROW:
0891: Object obj = _factory.makeObject(key);
0892: pair = new ObjectTimestampPair(obj);
0893: break;
0894: case WHEN_EXHAUSTED_FAIL:
0895: throw new NoSuchElementException();
0896: case WHEN_EXHAUSTED_BLOCK:
0897: try {
0898: if (_maxWait <= 0) {
0899: wait();
0900: } else {
0901: // this code may be executed again after a notify then continue cycle
0902: // so, need to calculate the amount of time to wait
0903: final long elapsed = (System
0904: .currentTimeMillis() - starttime);
0905: final long waitTime = _maxWait
0906: - elapsed;
0907: if (waitTime > 0) {
0908: wait(waitTime);
0909: }
0910: }
0911: } catch (InterruptedException e) {
0912: // ignored
0913: }
0914: if (_maxWait > 0
0915: && ((System.currentTimeMillis() - starttime) >= _maxWait)) {
0916: throw new NoSuchElementException(
0917: "Timeout waiting for idle object");
0918: } else {
0919: continue; // keep looping
0920: }
0921: default:
0922: throw new IllegalArgumentException(
0923: "whenExhaustedAction "
0924: + _whenExhaustedAction
0925: + " not recognized.");
0926: }
0927: }
0928: }
0929: _factory.activateObject(key, pair.value);
0930: if (_testOnBorrow
0931: && !_factory.validateObject(key, pair.value)) {
0932: _factory.destroyObject(key, pair.value);
0933: if (newlyCreated) {
0934: throw new NoSuchElementException(
0935: "Could not create a validated object");
0936: } // else keep looping
0937: } else {
0938: incrementActiveCount(key);
0939: return pair.value;
0940: }
0941: }
0942: }
0943:
0944: public synchronized void clear() {
0945: for (Iterator keyiter = _poolMap.keySet().iterator(); keyiter
0946: .hasNext();) {
0947: Object key = keyiter.next();
0948: final LinkedList list = (LinkedList) (_poolMap.get(key));
0949: for (Iterator it = list.iterator(); it.hasNext();) {
0950: try {
0951: _factory.destroyObject(key,
0952: ((ObjectTimestampPair) (it.next())).value);
0953: } catch (Exception e) {
0954: // ignore error, keep destroying the rest
0955: }
0956: it.remove();
0957: }
0958: }
0959: _poolMap.clear();
0960: if (_recentlyEvictedKeys != null) {
0961: _recentlyEvictedKeys.clear();
0962: }
0963: _totalIdle = 0;
0964: notifyAll();
0965: }
0966:
0967: /**
0968: * Method clears oldest 15% of objects in pool. The method sorts the
0969: * objects into a TreeMap and then iterates the first 15% for removal
0970: */
0971: public synchronized void clearOldest() {
0972: // build sorted map of idle objects
0973: TreeMap map = new TreeMap();
0974: for (Iterator keyiter = _poolMap.keySet().iterator(); keyiter
0975: .hasNext();) {
0976: Object key = keyiter.next();
0977: LinkedList list = (LinkedList) _poolMap.get(key);
0978: for (Iterator it = list.iterator(); it.hasNext();) {
0979: // each item into the map uses the objectimestamppair object
0980: // as the key. It then gets sorted based on the timstamp field
0981: // each value in the map is the parent list it belongs in.
0982: ObjectTimestampPair pair = (ObjectTimestampPair) it
0983: .next();
0984: map.put(pair, key);
0985: }
0986: }
0987:
0988: // Now iterate created map and kill the first 15% plus one to account for zero
0989: Set setPairKeys = map.entrySet();
0990: int itemsToRemove = ((int) (map.size() * 0.15)) + 1;
0991:
0992: Iterator iter = setPairKeys.iterator();
0993: while (iter.hasNext() && itemsToRemove > 0) {
0994: Map.Entry entry = (Map.Entry) iter.next();
0995: // kind of backwards on naming. In the map, each key is the objecttimestamppair
0996: // because it has the ordering with the timestamp value. Each value that the
0997: // key references is the key of the list it belongs to.
0998: Object key = entry.getValue();
0999: ObjectTimestampPair pairTimeStamp = (ObjectTimestampPair) entry
1000: .getKey();
1001: LinkedList list = (LinkedList) _poolMap.get(key);
1002: list.remove(pairTimeStamp);
1003:
1004: try {
1005: _factory.destroyObject(key, pairTimeStamp.value);
1006: } catch (Exception e) {
1007: // ignore error, keep destroying the rest
1008: }
1009: // if that was the last object for that key, drop that pool
1010: if (list.isEmpty()) {
1011: _poolMap.remove(key);
1012: }
1013: _totalIdle--;
1014: itemsToRemove--;
1015: }
1016: notifyAll();
1017: }
1018:
1019: public synchronized void clear(Object key) {
1020: LinkedList pool = (LinkedList) (_poolMap.remove(key));
1021: if (null == pool) {
1022: return;
1023: } else {
1024: for (Iterator it = pool.iterator(); it.hasNext();) {
1025: try {
1026: _factory.destroyObject(key,
1027: ((ObjectTimestampPair) (it.next())).value);
1028: } catch (Exception e) {
1029: // ignore error, keep destroying the rest
1030: }
1031: it.remove();
1032: _totalIdle--;
1033: }
1034: }
1035: notifyAll();
1036: }
1037:
1038: public synchronized int getNumActive() {
1039: return _totalActive;
1040: }
1041:
1042: public synchronized int getNumIdle() {
1043: return _totalIdle;
1044: }
1045:
1046: public synchronized int getNumActive(Object key) {
1047: return getActiveCount(key);
1048: }
1049:
1050: public synchronized int getNumIdle(Object key) {
1051: try {
1052: return ((LinkedList) (_poolMap.get(key))).size();
1053: } catch (Exception e) {
1054: return 0;
1055: }
1056: }
1057:
1058: public synchronized void returnObject(Object key, Object obj)
1059: throws Exception {
1060:
1061: // if we need to validate this object, do so
1062: boolean success = true; // whether or not this object passed validation
1063: if (_testOnReturn && !_factory.validateObject(key, obj)) {
1064: success = false;
1065: try {
1066: _factory.destroyObject(key, obj);
1067: } catch (Exception e) {
1068: // ignored
1069: }
1070: } else {
1071: try {
1072: _factory.passivateObject(key, obj);
1073: } catch (Exception e) {
1074: success = false;
1075: }
1076: }
1077:
1078: boolean shouldDestroy = false;
1079: // grab the pool (list) of objects associated with the given key
1080: LinkedList pool = (LinkedList) (_poolMap.get(key));
1081: // if it doesn't exist, create it
1082: if (null == pool) {
1083: pool = new LinkedList();
1084: _poolMap.put(key, pool);
1085: }
1086: decrementActiveCount(key);
1087: // if there's no space in the pool, flag the object for destruction
1088: // else if we passivated succesfully, return it to the pool
1089: if (_maxIdle >= 0 && (pool.size() >= _maxIdle)) {
1090: shouldDestroy = true;
1091: } else if (success) {
1092: pool.addLast(new ObjectTimestampPair(obj));
1093: _totalIdle++;
1094: }
1095: notifyAll();
1096:
1097: if (shouldDestroy) {
1098: try {
1099: _factory.destroyObject(key, obj);
1100: } catch (Exception e) {
1101: // ignored?
1102: }
1103: }
1104: }
1105:
1106: public synchronized void invalidateObject(Object key, Object obj)
1107: throws Exception {
1108: try {
1109: _factory.destroyObject(key, obj);
1110: } finally {
1111: decrementActiveCount(key);
1112: notifyAll(); // _totalActive has changed
1113: }
1114: }
1115:
1116: public synchronized void addObject(Object key) throws Exception {
1117: Object obj = _factory.makeObject(key);
1118: incrementActiveCount(key); // returnObject will decrement this
1119: returnObject(key, obj);
1120: }
1121:
1122: /**
1123: * Registers a key for pool control.
1124: *
1125: * If <i>populateImmediately</i> is <code>true</code>, the pool will immediately commence
1126: * a sustain cycle. If <i>populateImmediately</i> is <code>false</code>, the pool will be
1127: * populated when the next schedules sustain task is run.
1128: *
1129: * @param key - The key to register for pool control.
1130: * @param populateImmediately - If this is <code>true</code>, the pool
1131: * will start a sustain cycle immediately.
1132: */
1133: public synchronized void preparePool(Object key,
1134: boolean populateImmediately) {
1135: LinkedList pool = (LinkedList) (_poolMap.get(key));
1136: if (null == pool) {
1137: pool = new LinkedList();
1138: _poolMap.put(key, pool);
1139: }
1140:
1141: if (populateImmediately) {
1142: try {
1143: // Create the pooled objects
1144: ensureMinIdle(key);
1145: } catch (Exception e) {
1146: //Do nothing
1147: }
1148: }
1149: }
1150:
1151: public synchronized void close() throws Exception {
1152: clear();
1153: _poolMap = null;
1154: _activeMap = null;
1155: _recentlyEvictedKeys = null;
1156: if (null != _evictor) {
1157: _evictor.cancel();
1158: _evictor = null;
1159: }
1160: }
1161:
1162: public synchronized void setFactory(
1163: KeyedPoolableObjectFactory factory)
1164: throws IllegalStateException {
1165: if (0 < getNumActive()) {
1166: throw new IllegalStateException(
1167: "Objects are already active");
1168: } else {
1169: clear();
1170: _factory = factory;
1171: }
1172: }
1173:
1174: public synchronized void evict() throws Exception {
1175: Object key = null;
1176: if (_recentlyEvictedKeys == null) {
1177: _recentlyEvictedKeys = new HashSet(_poolMap.size());
1178: }
1179: Set remainingKeys = new HashSet(_poolMap.keySet());
1180: remainingKeys.removeAll(_recentlyEvictedKeys);
1181: Iterator keyIter = remainingKeys.iterator();
1182:
1183: ListIterator objIter = null;
1184:
1185: for (int i = 0, m = getNumTests(); i < m; i++) {
1186: if (_poolMap.size() > 0) {
1187: // Find next idle object pool key to work on
1188: if (key == null) {
1189: if (!keyIter.hasNext()) {
1190: _recentlyEvictedKeys.clear();
1191: remainingKeys = new HashSet(_poolMap.keySet());
1192: keyIter = remainingKeys.iterator();
1193: }
1194: if (!keyIter.hasNext()) {
1195: // done, there are no keyed pools
1196: return;
1197: }
1198: key = keyIter.next();
1199: }
1200:
1201: // if we don't have a keyed object pool iterator
1202: if (objIter == null) {
1203: final LinkedList list = (LinkedList) _poolMap
1204: .get(key);
1205: if (_evictLastIndex < 0
1206: || _evictLastIndex > list.size()) {
1207: _evictLastIndex = list.size();
1208: }
1209: objIter = list.listIterator(_evictLastIndex);
1210: }
1211:
1212: // if the _evictionCursor has a previous object, then test it
1213: if (objIter.hasPrevious()) {
1214: ObjectTimestampPair pair = (ObjectTimestampPair) (objIter
1215: .previous());
1216: boolean removeObject = false;
1217: if (_minEvictableIdleTimeMillis > 0
1218: && System.currentTimeMillis() - pair.tstamp > _minEvictableIdleTimeMillis) {
1219: removeObject = true;
1220: }
1221: if (_testWhileIdle && removeObject == false) {
1222: boolean active = false;
1223: try {
1224: _factory.activateObject(key, pair.value);
1225: active = true;
1226: } catch (Exception e) {
1227: removeObject = true;
1228: }
1229: if (active) {
1230: if (!_factory.validateObject(key,
1231: pair.value)) {
1232: removeObject = true;
1233: } else {
1234: try {
1235: _factory.passivateObject(key,
1236: pair.value);
1237: } catch (Exception e) {
1238: removeObject = true;
1239: }
1240: }
1241: }
1242: }
1243: if (removeObject) {
1244: try {
1245: objIter.remove();
1246: _totalIdle--;
1247: _factory.destroyObject(key, pair.value);
1248:
1249: // Do not remove the key from the _poolList or _poolmap, even if the list
1250: // stored in the _poolMap for this key is empty when the
1251: // {@link #getMinIdle <i>minIdle</i>} is > 0.
1252: //
1253: // Otherwise if it was the last object for that key, drop that pool
1254: if ((_minIdle == 0)
1255: && (((LinkedList) (_poolMap
1256: .get(key))).isEmpty())) {
1257: _poolMap.remove(key);
1258: }
1259: } catch (Exception e) {
1260: ; // ignored
1261: }
1262: }
1263: } else {
1264: // else done evicting keyed pool
1265: _recentlyEvictedKeys.add(key);
1266: _evictLastIndex = -1;
1267: objIter = null;
1268: }
1269: }
1270: }
1271: }
1272:
1273: /**
1274: * Iterates through all the known keys and creates any necessary objects to maintain
1275: * the minimum level of pooled objects.
1276: * @see #getMinIdle
1277: * @see #setMinIdle
1278: * @throws Exception If there was an error whilst creating the pooled objects.
1279: */
1280: private synchronized void ensureMinIdle() throws Exception {
1281: Iterator iterator = _poolMap.keySet().iterator();
1282:
1283: //Check if should sustain the pool
1284: if (_minIdle > 0) {
1285: // Loop through all elements in _poolList
1286: // Find out the total number of max active and max idle for that class
1287: // If the number is less than the minIdle, do creation loop to boost numbers
1288: // Increment idle count + 1
1289: while (iterator.hasNext()) {
1290: //Get the next key to process
1291: Object key = iterator.next();
1292: ensureMinIdle(key);
1293: }
1294: }
1295: }
1296:
1297: /**
1298: * Re-creates any needed objects to maintain the minimum levels of
1299: * pooled objects for the specified key.
1300: *
1301: * This method uses {@link #calculateDefecit} to calculate the number
1302: * of objects to be created. {@link #calculateDefecit} can be overridden to
1303: * provide a different method of calculating the number of objects to be
1304: * created.
1305: * @param key The key to process
1306: * @throws Exception If there was an error whilst creating the pooled objects
1307: */
1308: private synchronized void ensureMinIdle(Object key)
1309: throws Exception {
1310: // Calculate current pool objects
1311: int numberToCreate = calculateDefecit(key);
1312:
1313: //Create required pool objects, if none to create, this loop will not be run.
1314: for (int i = 0; i < numberToCreate; i++) {
1315: addObject(key);
1316: }
1317: }
1318:
1319: //--- non-public methods ----------------------------------------
1320:
1321: /**
1322: * Start the eviction thread or service, or when
1323: * <i>delay</i> is non-positive, stop it
1324: * if it is already running.
1325: */
1326: protected synchronized void startEvictor(long delay) {
1327: if (null != _evictor) {
1328: _evictor.cancel();
1329: _evictor = null;
1330: }
1331: if (delay > 0) {
1332: _evictor = new Evictor();
1333: GenericObjectPool.EVICTION_TIMER.schedule(_evictor, delay,
1334: delay);
1335: }
1336: }
1337:
1338: synchronized String debugInfo() {
1339: StringBuffer buf = new StringBuffer();
1340: buf.append("Active: ").append(getNumActive()).append("\n");
1341: buf.append("Idle: ").append(getNumIdle()).append("\n");
1342: Iterator it = _poolMap.keySet().iterator();
1343: while (it.hasNext()) {
1344: buf.append("\t").append(_poolMap.get(it.next())).append(
1345: "\n");
1346: }
1347: return buf.toString();
1348: }
1349:
1350: private int getNumTests() {
1351: if (_numTestsPerEvictionRun >= 0) {
1352: return _numTestsPerEvictionRun;
1353: } else {
1354: return (int) (Math.ceil((double) _totalIdle
1355: / Math.abs((double) _numTestsPerEvictionRun)));
1356: }
1357: }
1358:
1359: private void incrementActiveCount(Object key) {
1360: _totalActive++;
1361: Integer active = (Integer) (_activeMap.get(key));
1362: if (null == active) {
1363: _activeMap.put(key, new Integer(1));
1364: } else {
1365: _activeMap.put(key, new Integer(active.intValue() + 1));
1366: }
1367: }
1368:
1369: private void decrementActiveCount(Object key) {
1370: _totalActive--;
1371: Integer active = (Integer) (_activeMap.get(key));
1372: if (null == active) {
1373: // do nothing, either null or zero is OK
1374: } else if (active.intValue() <= 1) {
1375: _activeMap.remove(key);
1376: } else {
1377: _activeMap.put(key, new Integer(active.intValue() - 1));
1378: }
1379: }
1380:
1381: private int getActiveCount(Object key) {
1382: int active = 0;
1383: Integer act = (Integer) (_activeMap.get(key));
1384: if (null != act) {
1385: active = act.intValue();
1386: }
1387: return active;
1388: }
1389:
1390: /**
1391: * This returns the number of objects to create during the pool
1392: * sustain cycle. This will ensure that the minimum number of idle
1393: * connections is maintained without going past the maxPool value.
1394: * <p>
1395: * This method has been left public so derived classes can override
1396: * the way the defecit is calculated. ie... Increase/decrease the pool
1397: * size at certain times of day to accomodate for usage patterns.
1398: *
1399: * @param key - The key of the pool to calculate the number of
1400: * objects to be re-created
1401: * @return The number of objects to be created
1402: */
1403: private int calculateDefecit(Object key) {
1404: int objectDefecit = 0;
1405:
1406: //Calculate no of objects needed to be created, in order to have
1407: //the number of pooled objects < maxActive();
1408: objectDefecit = getMinIdle() - getNumIdle(key);
1409: if (getMaxActive() > 0) {
1410: int growLimit = Math.max(0, getMaxActive()
1411: - getNumActive(key) - getNumIdle(key));
1412: objectDefecit = Math.min(objectDefecit, growLimit);
1413: }
1414:
1415: // Take the maxTotal limit into account
1416: if (getMaxTotal() > 0) {
1417: int growLimit = Math.max(0, getMaxTotal() - getNumActive()
1418: - getNumIdle());
1419: objectDefecit = Math.min(objectDefecit, growLimit);
1420: }
1421:
1422: return objectDefecit;
1423: }
1424:
1425: //--- inner classes ----------------------------------------------
1426:
1427: /**
1428: * A simple "struct" encapsulating an object instance and a timestamp.
1429: *
1430: * Implements Comparable, objects are sorted from old to new.
1431: *
1432: * This is also used by {@link GenericObjectPool}.
1433: */
1434: static class ObjectTimestampPair implements Comparable {
1435: Object value;
1436: long tstamp;
1437:
1438: ObjectTimestampPair(Object val) {
1439: this (val, System.currentTimeMillis());
1440: }
1441:
1442: ObjectTimestampPair(Object val, long time) {
1443: value = val;
1444: tstamp = time;
1445: }
1446:
1447: public String toString() {
1448: return value + ";" + tstamp;
1449: }
1450:
1451: public int compareTo(Object obj) {
1452: return compareTo((ObjectTimestampPair) obj);
1453: }
1454:
1455: public int compareTo(ObjectTimestampPair other) {
1456: return (int) (this .tstamp - other.tstamp);
1457: }
1458: }
1459:
1460: /**
1461: * The idle object evictor {@link TimerTask}.
1462: * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
1463: */
1464: private class Evictor extends TimerTask {
1465: public void run() {
1466: //Evict from the pool
1467: try {
1468: evict();
1469: } catch (Exception e) {
1470: // ignored
1471: }
1472: //Re-create the connections.
1473: try {
1474: ensureMinIdle();
1475: } catch (Exception e) {
1476: // ignored
1477: }
1478: }
1479: }
1480:
1481: /**
1482: * A simple "struct" encapsulating the
1483: * configuration information for a {@link GenericKeyedObjectPool}.
1484: * @see GenericKeyedObjectPool#GenericKeyedObjectPool(KeyedPoolableObjectFactory,GenericKeyedObjectPool.Config)
1485: * @see GenericKeyedObjectPool#setConfig
1486: */
1487: public static class Config {
1488: public int maxIdle = GenericKeyedObjectPool.DEFAULT_MAX_IDLE;
1489: public int maxActive = GenericKeyedObjectPool.DEFAULT_MAX_ACTIVE;
1490: public int maxTotal = GenericKeyedObjectPool.DEFAULT_MAX_TOTAL;
1491: public int minIdle = GenericKeyedObjectPool.DEFAULT_MIN_IDLE;
1492: public long maxWait = GenericKeyedObjectPool.DEFAULT_MAX_WAIT;
1493: public byte whenExhaustedAction = GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION;
1494: public boolean testOnBorrow = GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW;
1495: public boolean testOnReturn = GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN;
1496: public boolean testWhileIdle = GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE;
1497: public long timeBetweenEvictionRunsMillis = GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
1498: public int numTestsPerEvictionRun = GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
1499: public long minEvictableIdleTimeMillis = GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
1500: }
1501:
1502: //--- protected attributes ---------------------------------------
1503:
1504: /**
1505: * The cap on the number of idle instances in the pool (per key).
1506: * @see #setMaxIdle
1507: * @see #getMaxIdle
1508: */
1509: private int _maxIdle = DEFAULT_MAX_IDLE;
1510:
1511: /**
1512: * The minimum no of idle objects to keep in the pool (per key)
1513: * @see #setMinIdle
1514: * @see #getMinIdle
1515: */
1516: private int _minIdle = DEFAULT_MIN_IDLE;
1517:
1518: /**
1519: * The cap on the number of active instances from the pool (per key).
1520: * @see #setMaxActive
1521: * @see #getMaxActive
1522: */
1523: private int _maxActive = DEFAULT_MAX_ACTIVE;
1524:
1525: /**
1526: * The cap on the total number of instances from the pool if non-positive.
1527: * @see #setMaxTotal
1528: * @see #getMaxTotal
1529: */
1530: private int _maxTotal = DEFAULT_MAX_TOTAL;
1531:
1532: /**
1533: * The maximum amount of time (in millis) the
1534: * {@link #borrowObject} method should block before throwing
1535: * an exception when the pool is exhausted and the
1536: * {@link #getWhenExhaustedAction "when exhausted" action} is
1537: * {@link #WHEN_EXHAUSTED_BLOCK}.
1538: *
1539: * When less than 0, the {@link #borrowObject} method
1540: * may block indefinitely.
1541: *
1542: * @see #setMaxWait
1543: * @see #getMaxWait
1544: * @see #WHEN_EXHAUSTED_BLOCK
1545: * @see #setWhenExhaustedAction
1546: * @see #getWhenExhaustedAction
1547: */
1548: private long _maxWait = DEFAULT_MAX_WAIT;
1549:
1550: /**
1551: * The action to take when the {@link #borrowObject} method
1552: * is invoked when the pool is exhausted (the maximum number
1553: * of "active" objects has been reached).
1554: *
1555: * @see #WHEN_EXHAUSTED_BLOCK
1556: * @see #WHEN_EXHAUSTED_FAIL
1557: * @see #WHEN_EXHAUSTED_GROW
1558: * @see #DEFAULT_WHEN_EXHAUSTED_ACTION
1559: * @see #setWhenExhaustedAction
1560: * @see #getWhenExhaustedAction
1561: */
1562: private byte _whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION;
1563:
1564: /**
1565: * When <tt>true</tt>, objects will be
1566: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
1567: * before being returned by the {@link #borrowObject}
1568: * method. If the object fails to validate,
1569: * it will be dropped from the pool, and we will attempt
1570: * to borrow another.
1571: *
1572: * @see #setTestOnBorrow
1573: * @see #getTestOnBorrow
1574: */
1575: private boolean _testOnBorrow = DEFAULT_TEST_ON_BORROW;
1576:
1577: /**
1578: * When <tt>true</tt>, objects will be
1579: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
1580: * before being returned to the pool within the
1581: * {@link #returnObject}.
1582: *
1583: * @see #getTestOnReturn
1584: * @see #setTestOnReturn
1585: */
1586: private boolean _testOnReturn = DEFAULT_TEST_ON_RETURN;
1587:
1588: /**
1589: * When <tt>true</tt>, objects will be
1590: * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
1591: * by the idle object evictor (if any). If an object
1592: * fails to validate, it will be dropped from the pool.
1593: *
1594: * @see #setTestWhileIdle
1595: * @see #getTestWhileIdle
1596: * @see #getTimeBetweenEvictionRunsMillis
1597: * @see #setTimeBetweenEvictionRunsMillis
1598: */
1599: private boolean _testWhileIdle = DEFAULT_TEST_WHILE_IDLE;
1600:
1601: /**
1602: * The number of milliseconds to sleep between runs of the
1603: * idle object evictor thread.
1604: * When non-positive, no idle object evictor thread will be
1605: * run.
1606: *
1607: * @see #setTimeBetweenEvictionRunsMillis
1608: * @see #getTimeBetweenEvictionRunsMillis
1609: */
1610: private long _timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
1611:
1612: /**
1613: * The number of objects to examine during each run of the
1614: * idle object evictor thread (if any).
1615: * <p>
1616: * When a negative value is supplied, <tt>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</tt>
1617: * tests will be run. I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
1618: * idle objects will be tested per run.
1619: *
1620: * @see #setNumTestsPerEvictionRun
1621: * @see #getNumTestsPerEvictionRun
1622: * @see #getTimeBetweenEvictionRunsMillis
1623: * @see #setTimeBetweenEvictionRunsMillis
1624: */
1625: private int _numTestsPerEvictionRun = DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
1626:
1627: /**
1628: * The minimum amount of time an object may sit idle in the pool
1629: * before it is eligable for eviction by the idle object evictor
1630: * (if any).
1631: * When non-positive, no objects will be evicted from the pool
1632: * due to idle time alone.
1633: *
1634: * @see #setMinEvictableIdleTimeMillis
1635: * @see #getMinEvictableIdleTimeMillis
1636: * @see #getTimeBetweenEvictionRunsMillis
1637: * @see #setTimeBetweenEvictionRunsMillis
1638: */
1639: private long _minEvictableIdleTimeMillis = DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
1640:
1641: /** My hash of pools (CursorableLinkedLists). */
1642: private HashMap _poolMap = null;
1643:
1644: /** Count of active objects, per key. */
1645: private HashMap _activeMap = null;
1646:
1647: /** The total number of active instances. */
1648: private int _totalActive = 0;
1649:
1650: /** The total number of idle instances. */
1651: private int _totalIdle = 0;
1652:
1653: /** My {@link KeyedPoolableObjectFactory}. */
1654: private KeyedPoolableObjectFactory _factory = null;
1655:
1656: /**
1657: * My idle object eviction {@link TimerTask}, if any.
1658: */
1659: private Evictor _evictor = null;
1660:
1661: /**
1662: * Idle object pool keys that have been evicted recently.
1663: */
1664: private Set _recentlyEvictedKeys = null;
1665:
1666: /**
1667: * Position in the _pool where the _evictor last stopped.
1668: */
1669: private int _evictLastIndex = -1;
1670: }
|