    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.pool;
    019
    020    import java.util.Collection;
    021    import java.util.HashMap;
    022    import java.util.Iterator;
    023    import java.util.Map;
    024    import java.util.NoSuchElementException;
    025    import java.util.Timer;
    026    import java.util.TimerTask;
    027    import java.util.Collections;
    028
    029    /**
    030     * This class consists exclusively of static methods that operate on or return ObjectPool
    031     * or KeyedObjectPool related interfaces.
    032     *
    033     * @author Sandy McArthur
    034     * @version $Revision: 1086470 $ $Date: 2011-03-28 21:30:47 -0700 (Mon, 28 Mar 2011) $
    035     * @since Pool 1.3
    036     */
    037    public final class PoolUtils {
    038
    039        /**
    040         * Timer used to periodically check pools idle object count.
    041         * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated.
    042         */
    043        private static Timer MIN_IDLE_TIMER; //@GuardedBy("this")
    044
    045        /**
    046         * PoolUtils instances should NOT be constructed in standard programming.
    047         * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
    048         * This constructor is public to permit tools that require a JavaBean instance to operate.
    049         */
    050        public PoolUtils() {
    051        }
    052
    053        /**
    054         * Should the supplied Throwable be re-thrown (eg if it is an instance of
    055         * one of the Throwables that should never be swallowed). Used by the pool
    056         * error handling for operations that throw exceptions that normally need to
    057         * be ignored.
    058         * @param t The Throwable to check
    059         * @throws ThreadDeath if that is passed in
    060         * @throws VirtualMachineError if that is passed in
    061         * @since Pool 1.5.5
    062         */
    063        public static void checkRethrow(Throwable t) {
    064            if (t instanceof ThreadDeath) {
    065                throw (ThreadDeath) t;
    066            }
    067            if (t instanceof VirtualMachineError) {
    068                throw (VirtualMachineError) t;
    069            }
    070            // All other instances of Throwable will be silently swallowed
    071        }
    072
    073        /**
    074         * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
    075         * needed. This method is the equivalent of calling
    076         * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}.
    077         *
    078         * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
    079         * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key.
    080         * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>.
    081         * @see #adapt(KeyedPoolableObjectFactory, Object)
    082         * @since Pool 1.3
    083         */
    084        public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
    085            return adapt(keyedFactory, new Object());
    086        }
    087
    088        /**
    089         * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
    090         * needed using the specified <code>key</code> when delegating.
    091         *
    092         * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
    093         * @param key the key to use when delegating.
    094         * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key.
    095         * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>.
    096         * @see #adapt(KeyedPoolableObjectFactory)
    097         * @since Pool 1.3
    098         */
    099        public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException {
    100            return new PoolableObjectFactoryAdaptor(keyedFactory, key);
    101        }
    102
    103        /**
    104         * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is
    105         * needed. The key is ignored.
    106         *
    107         * @param factory the {@link PoolableObjectFactory} to delegate to.
    108         * @return a {@link KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key.
    109         * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>.
    110         * @since Pool 1.3
    111         */
    112        public static KeyedPoolableObjectFactory adapt(final PoolableObjectFactory factory) throws IllegalArgumentException {
    113            return new KeyedPoolableObjectFactoryAdaptor(factory);
    114        }
    115
    116        /**
    117         * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the
    118         * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}.
    119         *
    120         * @param keyedPool the {@link KeyedObjectPool} to delegate to.
    121         * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with an internal key.
    122         * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>.
    123         * @see #adapt(KeyedObjectPool, Object)
    124         * @since Pool 1.3
    125         */
    126        public static ObjectPool adapt(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
    127            return adapt(keyedPool, new Object());
    128        }
    129
    130        /**
    131         * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the
    132         * specified <code>key</code> when delegating.
    133         *
    134         * @param keyedPool the {@link KeyedObjectPool} to delegate to.
    135         * @param key the key to use when delegating.
    136         * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with the specified key.
    137         * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
    138         * @see #adapt(KeyedObjectPool)
    139         * @since Pool 1.3
    140         */
    141        public static ObjectPool adapt(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
    142            return new ObjectPoolAdaptor(keyedPool, key);
    143        }
    144
    145        /**
    146         * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed.
    147         * The key is ignored.
    148         *
    149         * @param pool the {@link ObjectPool} to delegate to.
    150         * @return a {@link KeyedObjectPool} that delegates to <code>pool</code> ignoring the key.
    151         * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>.
    152         * @since Pool 1.3
    153         */
    154        public static KeyedObjectPool adapt(final ObjectPool pool) throws IllegalArgumentException {
    155            return new KeyedObjectPoolAdaptor(pool);
    156        }
    157
    158        /**
    159         * Wraps an <code>ObjectPool</code> and dynamically checks the type of objects borrowed and returned to the pool.
    160         * If an object is passed to the pool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
    161         *
    162         * @param pool the pool to enforce type safety on
    163         * @param type the class type to enforce.
    164         * @return an <code>ObjectPool</code> that will only allow objects of <code>type</code>
    165         * @since Pool 1.3
    166         */
    167        public static ObjectPool checkedPool(final ObjectPool pool, final Class type) {
    168            if (pool == null) {
    169                throw new IllegalArgumentException("pool must not be null.");
    170            }
    171            if (type == null) {
    172                throw new IllegalArgumentException("type must not be null.");
    173            }
    174            return new CheckedObjectPool(pool, type);
    175        }
    176
    177        /**
    178         * Wraps a <code>KeyedObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool.
    179         * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
    180         *
    181         * @param keyedPool the keyedPool to enforce type safety on
    182         * @param type the class type to enforce.
    183         * @return a <code>KeyedObjectPool</code> that will only allow objects of <code>type</code>
    184         * @since Pool 1.3
    185         */
    186        public static KeyedObjectPool checkedPool(final KeyedObjectPool keyedPool, final Class type) {
    187            if (keyedPool == null) {
    188                throw new IllegalArgumentException("keyedPool must not be null.");
    189            }
    190            if (type == null) {
    191                throw new IllegalArgumentException("type must not be null.");
    192            }
    193            return new CheckedKeyedObjectPool(keyedPool, type);
    194        }
    195
    196        /**
    197         * Periodically check the idle object count for the pool. At most one idle object will be added per period.
    198         * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed.
    199         *
    200         * @param pool the pool to check periodically.
    201         * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object.
    202         * @param period the frequency to check the number of idle objects in a pool, see
    203         *      {@link Timer#schedule(TimerTask, long, long)}.
    204         * @return the {@link TimerTask} that will periodically check the pools idle object count.
    205         * @throws IllegalArgumentException when <code>pool</code> is <code>null</code> or
    206         *      when <code>minIdle</code> is negative or when <code>period</code> isn't
    207         *      valid for {@link Timer#schedule(TimerTask, long, long)}.
    208         * @since Pool 1.3
    209         */
    210        public static TimerTask checkMinIdle(final ObjectPool pool, final int minIdle, final long period) throws IllegalArgumentException {
    211            if (pool == null) {
    212                throw new IllegalArgumentException("keyedPool must not be null.");
    213            }
    214            if (minIdle < 0) {
    215                throw new IllegalArgumentException("minIdle must be non-negative.");
    216            }
    217            final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle);
    218            getMinIdleTimer().schedule(task, 0L, period);
    219            return task;
    220        }
    221
    222        /**
    223         * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period.
    224         * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key
    225         * will be performed.
    226         *
    227         * @param keyedPool the keyedPool to check periodically.
    228         * @param key the key to check the idle count of.
    229         * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
    230         * @param period the frequency to check the number of idle objects in a keyedPool, see
    231         *      {@link Timer#schedule(TimerTask, long, long)}.
    232         * @return the {@link TimerTask} that will periodically check the pools idle object count.
    233         * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or
    234         *      when <code>minIdle</code> is negative or when <code>period</code> isn't
    235         *      valid for {@link Timer#schedule(TimerTask, long, long)}.
    236         * @since Pool 1.3
    237         */
    238        public static TimerTask checkMinIdle(final KeyedObjectPool keyedPool, final Object key, final int minIdle, final long period) throws IllegalArgumentException {
    239            if (keyedPool == null) {
    240                throw new IllegalArgumentException("keyedPool must not be null.");
    241            }
    242            if (key == null) {
    243                throw new IllegalArgumentException("key must not be null.");
    244            }
    245            if (minIdle < 0) {
    246                throw new IllegalArgumentException("minIdle must be non-negative.");
    247            }
    248            final TimerTask task = new KeyedObjectPoolMinIdleTimerTask(keyedPool, key, minIdle);
    249            getMinIdleTimer().schedule(task, 0L, period);
    250            return task;
    251        }
    252
    253        /**
    254         * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the keyedPool.
    255         * At most one idle object will be added per period.
    256         *
    257         * @param keyedPool the keyedPool to check periodically.
    258         * @param keys a collection of keys to check the idle object count.
    259         * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
    260         * @param period the frequency to check the number of idle objects in a keyedPool, see
    261         *      {@link Timer#schedule(TimerTask, long, long)}.
    262         * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count.
    263         * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the
    264         *      collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't
    265         *      valid for {@link Timer#schedule(TimerTask, long, long)}.
    266         * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
    267         * @since Pool 1.3
    268         */
    269        public static Map checkMinIdle(final KeyedObjectPool keyedPool, final Collection keys, final int minIdle, final long period) throws IllegalArgumentException {
    270            if (keys == null) {
    271                throw new IllegalArgumentException("keys must not be null.");
    272            }
    273            final Map tasks = new HashMap(keys.size());
    274            final Iterator iter = keys.iterator();
    275            while (iter.hasNext()) {
    276                final Object key = iter.next();
    277                final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
    278                tasks.put(key, task);
    279            }
    280            return tasks;
    281        }
    282
    283        /**
    284         * Call <code>addObject()</code> on <code>pool</code> <code>count</code> number of times.
    285         *
    286         * @param pool the pool to prefill.
    287         * @param count the number of idle objects to add.
    288         * @throws Exception when {@link ObjectPool#addObject()} fails.
    289         * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>.
    290         * @since Pool 1.3
    291         */
    292        public static void prefill(final ObjectPool pool, final int count) throws Exception, IllegalArgumentException {
    293            if (pool == null) {
    294                throw new IllegalArgumentException("pool must not be null.");
    295            }
    296            for (int i = 0; i < count; i++) {
    297                pool.addObject();
    298            }
    299        }
    300
    301        /**
    302         * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code>
    303         * number of times.
    304         *
    305         * @param keyedPool the keyedPool to prefill.
    306         * @param key the key to add objects for.
    307         * @param count the number of idle objects to add for <code>key</code>.
    308         * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
    309         * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
    310         * @since Pool 1.3
    311         */
    312        public static void prefill(final KeyedObjectPool keyedPool, final Object key, final int count) throws Exception, IllegalArgumentException {
    313            if (keyedPool == null) {
    314                throw new IllegalArgumentException("keyedPool must not be null.");
    315            }
    316            if (key == null) {
    317                throw new IllegalArgumentException("key must not be null.");
    318            }
    319            for (int i = 0; i < count; i++) {
    320                keyedPool.addObject(key);
    321            }
    322        }
    323
    324        /**
    325         * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for
    326         * <code>count</code> number of times. This has the same effect as calling
    327         * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection.
    328         *
    329         * @param keyedPool the keyedPool to prefill.
    330         * @param keys {@link Collection} of keys to add objects for.
    331         * @param count the number of idle objects to add for each <code>key</code>.
    332         * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
    333         * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or
    334         *      any value in <code>keys</code> is <code>null</code>.
    335         * @see #prefill(KeyedObjectPool, Object, int)
    336         * @since Pool 1.3
    337         */
    338        public static void prefill(final KeyedObjectPool keyedPool, final Collection keys, final int count) throws Exception, IllegalArgumentException {
    339            if (keys == null) {
    340                throw new IllegalArgumentException("keys must not be null.");
    341            }
    342            final Iterator iter = keys.iterator();
    343            while (iter.hasNext()) {
    344                prefill(keyedPool, iter.next(), count);
    345            }
    346        }
    347
    348        /**
    349         * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool.
    350         *
    351         * <p><b>Note:</b>
    352         * This should not be used on pool implementations that already provide proper synchronization
    353         * such as the pools provided in the Commons Pool library. Wrapping a pool that
    354         * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
    355         * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
    356         * </p>
    357         *
    358         * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool.
    359         * @return a synchronized view of the specified ObjectPool.
    360         * @since Pool 1.3
    361         */
    362        public static ObjectPool synchronizedPool(final ObjectPool pool) {
    363            if (pool == null) {
    364                throw new IllegalArgumentException("pool must not be null.");
    365            }
    366            /*
    367            assert !(pool instanceof GenericObjectPool)
    368                    : "GenericObjectPool is already thread-safe";
    369            assert !(pool instanceof SoftReferenceObjectPool)
    370                    : "SoftReferenceObjectPool is already thread-safe";
    371            assert !(pool instanceof StackObjectPool)
    372                    : "StackObjectPool is already thread-safe";
    373            assert !"org.apache.commons.pool.composite.CompositeObjectPool".equals(pool.getClass().getName())
    374                    : "CompositeObjectPools are already thread-safe";
    375            */
    376            return new SynchronizedObjectPool(pool);
    377        }
    378
    379        /**
    380         * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool.
    381         *
    382         * <p><b>Note:</b>
    383         * This should not be used on pool implementations that already provide proper synchronization
    384         * such as the pools provided in the Commons Pool library. Wrapping a pool that
    385         * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
    386         * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
    387         * </p>
    388         *
    389         * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool.
    390         * @return a synchronized view of the specified KeyedObjectPool.
    391         * @since Pool 1.3
    392         */
    393        public static KeyedObjectPool synchronizedPool(final KeyedObjectPool keyedPool) {
    394            if (keyedPool == null) {
    395                throw new IllegalArgumentException("keyedPool must not be null.");
    396            }
    397            /*
    398            assert !(keyedPool instanceof GenericKeyedObjectPool)
    399                    : "GenericKeyedObjectPool is already thread-safe";
    400            assert !(keyedPool instanceof StackKeyedObjectPool)
    401                    : "StackKeyedObjectPool is already thread-safe";
    402            assert !"org.apache.commons.pool.composite.CompositeKeyedObjectPool".equals(keyedPool.getClass().getName())
    403                    : "CompositeKeyedObjectPools are already thread-safe";
    404            */
    405            return new SynchronizedKeyedObjectPool(keyedPool);
    406        }
    407
    408        /**
    409         * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory.
    410         *
    411         * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory.
    412         * @return a synchronized view of the specified PoolableObjectFactory.
    413         * @since Pool 1.3
    414         */
    415        public static PoolableObjectFactory synchronizedPoolableFactory(final PoolableObjectFactory factory) {
    416            return new SynchronizedPoolableObjectFactory(factory);
    417        }
    418
    419        /**
    420         * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory.
    421         *
    422         * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory.
    423         * @return a synchronized view of the specified KeyedPoolableObjectFactory.
    424         * @since Pool 1.3
    425         */
    426        public static KeyedPoolableObjectFactory synchronizedPoolableFactory(final KeyedPoolableObjectFactory keyedFactory) {
    427            return new SynchronizedKeyedPoolableObjectFactory(keyedFactory);
    428        }
    429
    430        /**
    431         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
    432         * This is intended as an always thread-safe alternative to using an idle object evictor
    433         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
    434         * pools that experience load spikes.
    435         *
    436         * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible.
    437         * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
    438         * @see #erodingPool(ObjectPool, float)
    439         * @since Pool 1.4
    440         */
    441        public static ObjectPool erodingPool(final ObjectPool pool) {
    442            return erodingPool(pool, 1f);
    443        }
    444
    445        /**
    446         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
    447         * This is intended as an always thread-safe alternative to using an idle object evictor
    448         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
    449         * pools that experience load spikes.
    450         *
    451         * <p>
    452         * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
    453         * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
    454         * Values greater than 1 cause the pool to less frequently try to shrink it's size.
    455         * </p>
    456         *
    457         * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible.
    458         * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
    459         * If 0 &lt; factor &lt; 1 then the pool shrinks more aggressively.
    460         * If 1 &lt; factor then the pool shrinks less aggressively.
    461         * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
    462         * @see #erodingPool(ObjectPool)
    463         * @since Pool 1.4
    464         */
    465        public static ObjectPool erodingPool(final ObjectPool pool, final float factor) {
    466            if (pool == null) {
    467                throw new IllegalArgumentException("pool must not be null.");
    468            }
    469            if (factor <= 0f) {
    470                throw new IllegalArgumentException("factor must be positive.");
    471            }
    472            return new ErodingObjectPool(pool, factor);
    473        }
    474
    475        /**
    476         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
    477         * This is intended as an always thread-safe alternative to using an idle object evictor
    478         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
    479         * pools that experience load spikes.
    480         *
    481         * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when
    482         * possible.
    483         * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
    484         * @see #erodingPool(KeyedObjectPool, float)
    485         * @see #erodingPool(KeyedObjectPool, float, boolean)
    486         * @since Pool 1.4
    487         */
    488        public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool) {
    489            return erodingPool(keyedPool, 1f);
    490        }
    491
    492        /**
    493         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
    494         * This is intended as an always thread-safe alternative to using an idle object evictor
    495         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
    496         * pools that experience load spikes.
    497         *
    498         * <p>
    499         * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
    500         * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
    501         * Values greater than 1 cause the pool to less frequently try to shrink it's size.
    502         * </p>
    503         *
    504         * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when
    505         * possible.
    506         * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
    507         * If 0 &lt; factor &lt; 1 then the pool shrinks more aggressively.
    508         * If 1 &lt; factor then the pool shrinks less aggressively.
    509         * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
    510         * @see #erodingPool(KeyedObjectPool, float, boolean)
    511         * @since Pool 1.4
    512         */
    513        public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor) {
    514            return erodingPool(keyedPool, factor, false);
    515        }
    516
    517        /**
    518         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
    519         * This is intended as an always thread-safe alternative to using an idle object evictor
    520         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
    521         * pools that experience load spikes.
    522         *
    523         * <p>
    524         * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
    525         * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
    526         * Values greater than 1 cause the pool to less frequently try to shrink it's size.
    527         * </p>
    528         *
    529         * <p>
    530         * The perKey parameter determines if the pool shrinks on a whole pool basis or a per key basis.
    531         * When perKey is false, the keys do not have an effect on the rate at which the pool tries to
    532         * shrink it's size. When perKey is true, each key is shrunk independently.
    533         * </p>
    534         *
    535         * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when
    536         * possible.
    537         * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
    538         * If 0 &lt; factor &lt; 1 then the pool shrinks more aggressively.
    539         * If 1 &lt; factor then the pool shrinks less aggressively.
    540         * @param perKey when true, each key is treated independently.
    541         * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
    542         * @see #erodingPool(KeyedObjectPool)
    543         * @see #erodingPool(KeyedObjectPool, float)
    544         * @since Pool 1.4
    545         */
    546        public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor, final boolean perKey) {
    547            if (keyedPool == null) {
    548                throw new IllegalArgumentException("keyedPool must not be null.");
    549            }
    550            if (factor <= 0f) {
    551                throw new IllegalArgumentException("factor must be positive.");
    552            }
    553            if (perKey) {
    554                return new ErodingPerKeyKeyedObjectPool(keyedPool, factor);
    555            } else {
    556                return new ErodingKeyedObjectPool(keyedPool, factor);
    557            }
    558        }
    559
    560        /**
    561         * Get the <code>Timer</code> for checking keyedPool's idle count. Lazily create the {@link Timer} as needed.
    562         *
    563         * @return the {@link Timer} for checking keyedPool's idle count.
    564         * @since Pool 1.3
    565         */
    566        private static synchronized Timer getMinIdleTimer() {
    567            if (MIN_IDLE_TIMER == null) {
    568                MIN_IDLE_TIMER = new Timer(true);
    569            }
    570            return MIN_IDLE_TIMER;
    571        }
    572
    573        /**
    574         * Adaptor class that wraps and converts a KeyedPoolableObjectFactory with a fixed
    575         * key to a PoolableObjectFactory.
    576         */
    577        private static class PoolableObjectFactoryAdaptor implements PoolableObjectFactory {
    578            /** Fixed key */
    579            private final Object key;
    580
    581            /** Wrapped factory */
    582            private final KeyedPoolableObjectFactory keyedFactory;
    583
    584            /**
    585             * Create a PoolableObjectFactoryAdaptor wrapping the provided KeyedPoolableObjectFactory with the
    586             * given fixed key.
    587             *
    588             * @param keyedFactory KeyedPoolableObjectFactory that will manage objects
    589             * @param key fixed key
    590             * @throws IllegalArgumentException if either of the parameters is null
    591             */
    592            PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory keyedFactory, final Object key)
    593            throws IllegalArgumentException {
    594                if (keyedFactory == null) {
    595                    throw new IllegalArgumentException("keyedFactory must not be null.");
    596                }
    597                if (key == null) {
    598                    throw new IllegalArgumentException("key must not be null.");
    599                }
    600                this.keyedFactory = keyedFactory;
    601                this.key = key;
    602            }
    603
    604            /**
    605             * Create an object instance using the configured factory and key.
    606             *
    607             * @return new object instance
    608             */
    609            public Object makeObject() throws Exception {
    610                return keyedFactory.makeObject(key);
    611            }
    612
    613            /**
    614             * Destroy the object, passing the fixed key to the factory.
    615             *
    616             * @param obj object to destroy
    617             */
    618            public void destroyObject(final Object obj) throws Exception {
    619                keyedFactory.destroyObject(key, obj);
    620            }
    621
    622            /**
    623             * Validate the object, passing the fixed key to the factory.
    624             *
    625             * @param obj object to validate
    626             * @return true if validation is successful
    627             */
    628            public boolean validateObject(final Object obj) {
    629                return keyedFactory.validateObject(key, obj);
    630            }
    631
    632            /**
    633             * Activate the object, passing the fixed key to the factory.
    634             *
    635             * @param obj object to activate
    636             */
    637            public void activateObject(final Object obj) throws Exception {
    638                keyedFactory.activateObject(key, obj);
    639            }
    640
    641            /**
    642             * Passivate the object, passing the fixed key to the factory.
    643             *
    644             * @param obj object to passivate
    645             */
    646            public void passivateObject(final Object obj) throws Exception {
    647                keyedFactory.passivateObject(key, obj);
    648            }
    649
    650            /**
    651             * {@inheritDoc}
    652             */
    653            public String toString() {
    654                final StringBuffer sb = new StringBuffer();
    655                sb.append("PoolableObjectFactoryAdaptor");
    656                sb.append("{key=").append(key);
    657                sb.append(", keyedFactory=").append(keyedFactory);
    658                sb.append('}');
    659                return sb.toString();
    660            }
    661        }
    662
    663        /**
    664         * Adaptor class that turns a PoolableObjectFactory into a KeyedPoolableObjectFactory by
    665         * ignoring keys.
    666         */
    667        private static class KeyedPoolableObjectFactoryAdaptor implements KeyedPoolableObjectFactory {
    668
    669            /** Underlying PoolableObjectFactory */
    670            private final PoolableObjectFactory factory;
    671
    672            /**
    673             * Create a new KeyedPoolableObjectFactoryAdaptor using the given PoolableObjectFactory to
    674             * manage objects.
    675             *
    676             * @param factory wrapped PoolableObjectFactory
    677             * @throws IllegalArgumentException if the factory is null
    678             */
    679            KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory factory) throws IllegalArgumentException {
    680                if (factory == null) {
    681                    throw new IllegalArgumentException("factory must not be null.");
    682                }
    683                this.factory = factory;
    684            }
    685
    686            /**
    687             * Create a new object instance, ignoring the key
    688             *
    689             * @param key ignored
    690             * @return newly created object instance
    691             */
    692            public Object makeObject(final Object key) throws Exception {
    693                return factory.makeObject();
    694            }
    695
    696            /**
    697             * Destroy the object, ignoring the key.
    698             *
    699             * @param key ignored
    700             * @param obj instance to destroy
    701             */
    702            public void destroyObject(final Object key, final Object obj) throws Exception {
    703                factory.destroyObject(obj);
    704            }
    705
    706            /**
    707             * Validate the object, ignoring the key
    708             *
    709             * @param key ignored
    710             * @param obj object to validate
    711             * @return true if validation is successful
    712             */
    713            public boolean validateObject(final Object key, final Object obj) {
    714                return factory.validateObject(obj);
    715            }
    716
    717            /**
    718             * Activate the object, ignoring the key.
    719             *
    720             * @param key ignored
    721             * @param obj object to be activated
    722             */
    723            public void activateObject(final Object key, final Object obj) throws Exception {
    724                factory.activateObject(obj);
    725            }
    726
    727            /**
    728             * Passivate the object, ignoring the key.
    729             *
    730             * @param key ignored
    731             * @param obj object to passivate
    732             */
    733            public void passivateObject(final Object key, final Object obj) throws Exception {
    734                factory.passivateObject(obj);
    735            }
    736
    737            /**
    738             * {@inheritDoc}
    739             */
    740            public String toString() {
    741                final StringBuffer sb = new StringBuffer();
    742                sb.append("KeyedPoolableObjectFactoryAdaptor");
    743                sb.append("{factory=").append(factory);
    744                sb.append('}');
    745                return sb.toString();
    746            }
    747        }
    748
    749        /**
    750         * Adapts a KeyedObjectPool to make it an ObjectPool by fixing restricting to
    751         * a fixed key.
    752         */
    753        private static class ObjectPoolAdaptor implements ObjectPool {
    754
    755            /** Fixed key */
    756            private final Object key;
    757
    758            /** Underlying KeyedObjectPool */
    759            private final KeyedObjectPool keyedPool;
    760
    761            /**
    762             * Create a new ObjectPoolAdaptor using the provided KeyedObjectPool and fixed key.
    763             *
    764             * @param keyedPool underlying KeyedObjectPool
    765             * @param key fixed key
    766             * @throws IllegalArgumentException if either of the parameters is null
    767             */
    768            ObjectPoolAdaptor(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
    769                if (keyedPool == null) {
    770                    throw new IllegalArgumentException("keyedPool must not be null.");
    771                }
    772                if (key == null) {
    773                    throw new IllegalArgumentException("key must not be null.");
    774                }
    775                this.keyedPool = keyedPool;
    776                this.key = key;
    777            }
    778
    779            /**
    780             * {@inheritDoc}
    781             */
    782            public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
    783                return keyedPool.borrowObject(key);
    784            }
    785
    786            /**
    787             * {@inheritDoc}
    788             */
    789            public void returnObject(final Object obj) {
    790                try {
    791                    keyedPool.returnObject(key, obj);
    792                } catch (Exception e) {
    793                    // swallowed as of Pool 2
    794                }
    795            }
    796
    797            /**
    798             * {@inheritDoc}
    799             */
    800            public void invalidateObject(final Object obj) {
    801                try {
    802                    keyedPool.invalidateObject(key, obj);
    803                } catch (Exception e) {
    804                    // swallowed as of Pool 2
    805                }
    806            }
    807
    808            /**
    809             * {@inheritDoc}
    810             */
    811            public void addObject() throws Exception, IllegalStateException {
    812                keyedPool.addObject(key);
    813            }
    814
    815            /**
    816             * {@inheritDoc}
    817             */
    818            public int getNumIdle() throws UnsupportedOperationException {
    819                return keyedPool.getNumIdle(key);
    820            }
    821
    822            /**
    823             * {@inheritDoc}
    824             */
    825            public int getNumActive() throws UnsupportedOperationException {
    826                return keyedPool.getNumActive(key);
    827            }
    828
    829            /**
    830             * {@inheritDoc}
    831             */
    832            public void clear() throws Exception, UnsupportedOperationException {
    833                keyedPool.clear();
    834            }
    835
    836            /**
    837             * {@inheritDoc}
    838             */
    839            public void close() {
    840                try {
    841                    keyedPool.close();
    842                } catch (Exception e) {
    843                    // swallowed as of Pool 2
    844                }
    845            }
    846
    847            /**
    848             * Sets the PoolableObjectFactory for the pool.
    849             *
    850             * @param factory new PoolableObjectFactory
    851             * @deprecated to be removed in version 2.0
    852             */
    853            public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    854                keyedPool.setFactory(adapt(factory));
    855            }
    856
    857            /**
    858             * {@inheritDoc}
    859             */
    860            public String toString() {
    861                final StringBuffer sb = new StringBuffer();
    862                sb.append("ObjectPoolAdaptor");
    863                sb.append("{key=").append(key);
    864                sb.append(", keyedPool=").append(keyedPool);
    865                sb.append('}');
    866                return sb.toString();
    867            }
    868        }
    869
    870        /**
    871         * Adapts an ObjectPool to implement KeyedObjectPool by ignoring key arguments.
    872         */
    873        private static class KeyedObjectPoolAdaptor implements KeyedObjectPool {
    874
    875            /** Underlying pool */
    876            private final ObjectPool pool;
    877
    878            /**
    879             * Create a new KeyedObjectPoolAdaptor wrapping the given ObjectPool
    880             *
    881             * @param pool underlying object pool
    882             * @throws IllegalArgumentException if pool is null
    883             */
    884            KeyedObjectPoolAdaptor(final ObjectPool pool) throws IllegalArgumentException {
    885                if (pool == null) {
    886                    throw new IllegalArgumentException("pool must not be null.");
    887                }
    888                this.pool = pool;
    889            }
    890
    891            /**
    892             * Borrow and object from the pool, ignoring the key
    893             *
    894             * @param key ignored
    895             * @return newly created object instance
    896             */
    897            public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
    898                return pool.borrowObject();
    899            }
    900
    901            /**
    902             * Return and object to the pool, ignoring the key
    903             *
    904             * @param key ignored
    905             * @param obj object to return
    906             */
    907            public void returnObject(final Object key, final Object obj) {
    908                try {
    909                    pool.returnObject(obj);
    910                } catch (Exception e) {
    911                    // swallowed as of Pool 2
    912                }
    913            }
    914
    915            /**
    916             * Invalidate and object, ignoring the key
    917             *
    918             * @param obj object to invalidate
    919             * @param key ignored
    920             */
    921            public void invalidateObject(final Object key, final Object obj) {
    922                try {
    923                    pool.invalidateObject(obj);
    924                } catch (Exception e) {
    925                    // swallowed as of Pool 2
    926                }
    927            }
    928
    929            /**
    930             * Add an object to the pool, ignoring the key
    931             *
    932             * @param key ignored
    933             */
    934            public void addObject(final Object key) throws Exception, IllegalStateException {
    935                pool.addObject();
    936            }
    937
    938            /**
    939             * Return the number of objects idle in the pool, ignoring the key.
    940             *
    941             * @param key ignored
    942             * @return idle instance count
    943             */
    944            public int getNumIdle(final Object key) throws UnsupportedOperationException {
    945                return pool.getNumIdle();
    946            }
    947
    948            /**
    949             * Return the number of objects checked out from the pool, ignoring the key.
    950             *
    951             * @param key ignored
    952             * @return active instance count
    953             */
    954            public int getNumActive(final Object key) throws UnsupportedOperationException {
    955                return pool.getNumActive();
    956            }
    957
    958            /**
    959             * {@inheritDoc}
    960             */
    961            public int getNumIdle() throws UnsupportedOperationException {
    962                return pool.getNumIdle();
    963            }
    964
    965            /**
    966             * {@inheritDoc}
    967             */
    968            public int getNumActive() throws UnsupportedOperationException {
    969                return pool.getNumActive();
    970            }
    971
    972            /**
    973             * {@inheritDoc}
    974             */
    975            public void clear() throws Exception, UnsupportedOperationException {
    976                pool.clear();
    977            }
    978
    979            /**
    980             * Clear the pool, ignoring the key (has same effect as {@link #clear()}.
    981             *
    982             * @param key ignored.
    983             */
    984            public void clear(final Object key) throws Exception, UnsupportedOperationException {
    985                pool.clear();
    986            }
    987
    988            /**
    989             * {@inheritDoc}
    990             */
    991            public void close() {
    992                try {
    993                    pool.close();
    994                } catch (Exception e) {
    995                    // swallowed as of Pool 2
    996                }
    997            }
    998
    999            /**
    1000             * Sets the factory used to manage objects.
    1001             *
    1002             * @param factory new factory to use managing object instances
    1003             * @deprecated to be removed in version 2.0
    1004             */
    1005            public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    1006                pool.setFactory(adapt(factory));
    1007            }
    1008
    1009            /**
    1010             * {@inheritDoc}
    1011             */
    1012            public String toString() {
    1013                final StringBuffer sb = new StringBuffer();
    1014                sb.append("KeyedObjectPoolAdaptor");
    1015                sb.append("{pool=").append(pool);
    1016                sb.append('}');
    1017                return sb.toString();
    1018            }
    1019        }
    1020
    1021        /**
    1022         * An object pool that performs type checking on objects passed
    1023         * to pool methods.
    1024         *
    1025         */
    1026        private static class CheckedObjectPool implements ObjectPool {
    1027            /**
    1028             * Type of objects allowed in the pool. This should be a subtype of the return type of
    1029             * the underlying pool's associated object factory.
    1030             */
    1031            private final Class type;
    1032
    1033            /** Underlying object pool */
    1034            private final ObjectPool pool;
    1035
    1036            /**
    1037             * Create a CheckedObjectPool accepting objects of the given type using
    1038             * the given pool.
    1039             *
    1040             * @param pool underlying object pool
    1041             * @param type expected pooled object type
    1042             * @throws IllegalArgumentException if either parameter is null
    1043             */
    1044            CheckedObjectPool(final ObjectPool pool, final Class type) {
    1045                if (pool == null) {
    1046                    throw new IllegalArgumentException("pool must not be null.");
    1047                }
    1048                if (type == null) {
    1049                    throw new IllegalArgumentException("type must not be null.");
    1050                }
    1051                this.pool = pool;
    1052                this.type = type;
    1053            }
    1054
    1055            /**
    1056             * Borrow an object from the pool, checking its type.
    1057             *
    1058             * @return a type-checked object from the pool
    1059             * @throws ClassCastException if the object returned by the pool is not of the expected type
    1060             */
    1061            public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
    1062                final Object obj = pool.borrowObject();
    1063                if (type.isInstance(obj)) {
    1064                    return obj;
    1065                } else {
    1066                    throw new ClassCastException("Borrowed object is not of type: " + type.getName() + " was: " + obj);
    1067                }
    1068            }
    1069
    1070            /**
    1071             * Return an object to the pool, verifying that it is of the correct type.
    1072             *
    1073             * @param obj object to return
    1074             * @throws ClassCastException if obj is not of the expected type
    1075             */
    1076            public void returnObject(final Object obj) {
    1077                if (type.isInstance(obj)) {
    1078                    try {
    1079                        pool.returnObject(obj);
    1080                    } catch (Exception e) {
    1081                        // swallowed as of Pool 2
    1082                    }
    1083                } else {
    1084                    throw new ClassCastException("Returned object is not of type: " + type.getName() + " was: " + obj);
    1085                }
    1086            }
    1087
    1088            /**
    1089             * Invalidates an object from the pool, verifying that it is of the expected type.
    1090             *
    1091             * @param obj object to invalidate
    1092             * @throws ClassCastException if obj is not of the expected type
    1093             */
    1094            public void invalidateObject(final Object obj) {
    1095                if (type.isInstance(obj)) {
    1096                    try {
    1097                        pool.invalidateObject(obj);
    1098                    } catch (Exception e) {
    1099                        // swallowed as of Pool 2
    1100                    }
    1101                } else {
    1102                    throw new ClassCastException("Invalidated object is not of type: " + type.getName() + " was: " + obj);
    1103                }
    1104            }
    1105
    1106            /**
    1107             * {@inheritDoc}
    1108             */
    1109            public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
    1110                pool.addObject();
    1111            }
    1112
    1113            /**
    1114             * {@inheritDoc}
    1115             */
    1116            public int getNumIdle() throws UnsupportedOperationException {
    1117                return pool.getNumIdle();
    1118            }
    1119
    1120            /**
    1121             * {@inheritDoc}
    1122             */
    1123            public int getNumActive() throws UnsupportedOperationException {
    1124                return pool.getNumActive();
    1125            }
    1126
    1127            /**
    1128             * {@inheritDoc}
    1129             */
    1130            public void clear() throws Exception, UnsupportedOperationException {
    1131                pool.clear();
    1132            }
    1133
    1134            /**
    1135             * {@inheritDoc}
    1136             */
    1137            public void close() {
    1138                try {
    1139                    pool.close();
    1140                } catch (Exception e) {
    1141                    // swallowed as of Pool 2
    1142                }
    1143            }
    1144
    1145            /**
    1146             * Sets the object factory associated with the pool
    1147             *
    1148             * @param factory object factory
    1149             * @deprecated to be removed in version 2.0
    1150             */
    1151            public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    1152                pool.setFactory(factory);
    1153            }
    1154
    1155            /**
    1156             * {@inheritDoc}
    1157             */
    1158            public String toString() {
    1159                final StringBuffer sb = new StringBuffer();
    1160                sb.append("CheckedObjectPool");
    1161                sb.append("{type=").append(type);
    1162                sb.append(", pool=").append(pool);
    1163                sb.append('}');
    1164                return sb.toString();
    1165            }
    1166        }
    1167
    1168        /**
    1169         * A keyed object pool that performs type checking on objects passed
    1170         * to pool methods.
    1171         *
    1172         */
    1173        private static class CheckedKeyedObjectPool implements KeyedObjectPool {
    1174            /**
    1175             * Expected type of objects managed by the pool.  This should be
    1176             * a subtype of the return type of the object factory used by the pool.
    1177             */
    1178            private final Class type;
    1179
    1180            /** Underlying pool */
    1181            private final KeyedObjectPool keyedPool;
    1182
    1183            /**
    1184             * Create a new CheckedKeyedObjectPool from the given pool with given expected object type.
    1185             *
    1186             * @param keyedPool underlying pool
    1187             * @param type expected object type
    1188             * @throws IllegalArgumentException if either parameter is null
    1189             */
    1190            CheckedKeyedObjectPool(final KeyedObjectPool keyedPool, final Class type) {
    1191                if (keyedPool == null) {
    1192                    throw new IllegalArgumentException("keyedPool must not be null.");
    1193                }
    1194                if (type == null) {
    1195                    throw new IllegalArgumentException("type must not be null.");
    1196                }
    1197                this.keyedPool = keyedPool;
    1198                this.type = type;
    1199            }
    1200
    1201            /**
    1202             * Borrow an object from the pool, verifying correct return type.
    1203             *
    1204             * @param key pool key
    1205             * @return type-checked object from the pool under the given key
    1206             * @throws ClassCastException if the object returned by the pool is not of the expected type
    1207             */
    1208            public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
    1209                Object obj = keyedPool.borrowObject(key);
    1210                if (type.isInstance(obj)) {
    1211                    return obj;
    1212                } else {
    1213                    throw new ClassCastException("Borrowed object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
    1214                }
    1215            }
    1216
    1217            /**
    1218             * Return an object to the pool, checking its type.
    1219             *
    1220             * @param key the associated key (not type-checked)
    1221             * @param obj the object to return (type-checked)
    1222             * @throws ClassCastException if obj is not of the expected type
    1223             */
    1224            public void returnObject(final Object key, final Object obj) {
    1225                if (type.isInstance(obj)) {
    1226                    try {
    1227                        keyedPool.returnObject(key, obj);
    1228                    } catch (Exception e) {
    1229                        // swallowed as of Pool 2
    1230                    }
    1231                } else {
    1232                    throw new ClassCastException("Returned object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
    1233                }
    1234            }
    1235
    1236            /**
    1237             * Invalidate an object to the pool, checking its type.
    1238             *
    1239             * @param key the associated key (not type-checked)
    1240             * @param obj the object to return (type-checked)
    1241             * @throws ClassCastException if obj is not of the expected type
    1242             */
    1243            public void invalidateObject(final Object key, final Object obj) {
    1244                if (type.isInstance(obj)) {
    1245                    try {
    1246                        keyedPool.invalidateObject(key, obj);
    1247                    } catch (Exception e) {
    1248                        // swallowed as of Pool 2
    1249                    }
    1250                } else {
    1251                    throw new ClassCastException("Invalidated object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
    1252                }
    1253            }
    1254
    1255            /**
    1256             * {@inheritDoc}
    1257             */
    1258            public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
    1259                keyedPool.addObject(key);
    1260            }
    1261
    1262            /**
    1263             * {@inheritDoc}
    1264             */
    1265            public int getNumIdle(final Object key) throws UnsupportedOperationException {
    1266                return keyedPool.getNumIdle(key);
    1267            }
    1268
    1269            /**
    1270             * {@inheritDoc}
    1271             */
    1272            public int getNumActive(final Object key) throws UnsupportedOperationException {
    1273                return keyedPool.getNumActive(key);
    1274            }
    1275
    1276            /**
    1277             * {@inheritDoc}
    1278             */
    1279            public int getNumIdle() throws UnsupportedOperationException {
    1280                return keyedPool.getNumIdle();
    1281            }
    1282
    1283            /**
    1284             * {@inheritDoc}
    1285             */
    1286            public int getNumActive() throws UnsupportedOperationException {
    1287                return keyedPool.getNumActive();
    1288            }
    1289
    1290            /**
    1291             * {@inheritDoc}
    1292             */
    1293            public void clear() throws Exception, UnsupportedOperationException {
    1294                keyedPool.clear();
    1295            }
    1296
    1297            /**
    1298             * {@inheritDoc}
    1299             */
    1300            public void clear(final Object key) throws Exception, UnsupportedOperationException {
    1301                keyedPool.clear(key);
    1302            }
    1303
    1304            /**
    1305             * {@inheritDoc}
    1306             */
    1307            public void close() {
    1308                try {
    1309                    keyedPool.close();
    1310                } catch (Exception e) {
    1311                    // swallowed as of Pool 2
    1312                }
    1313            }
    1314
    1315            /**
    1316             * Sets the object factory associated with the pool
    1317             *
    1318             * @param factory object factory
    1319             * @deprecated to be removed in version 2.0
    1320             */
    1321            public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    1322                keyedPool.setFactory(factory);
    1323            }
    1324
    1325            /**
    1326             * {@inheritDoc}
    1327             */
    1328            public String toString() {
    1329                final StringBuffer sb = new StringBuffer();
    1330                sb.append("CheckedKeyedObjectPool");
    1331                sb.append("{type=").append(type);
    1332                sb.append(", keyedPool=").append(keyedPool);
    1333                sb.append('}');
    1334                return sb.toString();
    1335            }
    1336        }
    1337
    1338        /**
    1339         * Timer task that adds objects to the pool until the number of idle
    1340         * instances reaches the configured minIdle.  Note that this is not the
    1341         * same as the pool's minIdle setting.
    1342         *
    1343         */
    1344        private static class ObjectPoolMinIdleTimerTask extends TimerTask {
    1345
    1346            /** Minimum number of idle instances.  Not the same as pool.getMinIdle(). */
    1347            private final int minIdle;
    1348
    1349            /** Object pool */
    1350            private final ObjectPool pool;
    1351
    1352            /**
    1353             * Create a new ObjectPoolMinIdleTimerTask for the given pool with the given minIdle setting.
    1354             *
    1355             * @param pool object pool
    1356             * @param minIdle number of idle instances to maintain
    1357             * @throws IllegalArgumentException if the pool is null
    1358             */
    1359            ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) throws IllegalArgumentException {
    1360                if (pool == null) {
    1361                    throw new IllegalArgumentException("pool must not be null.");
    1362                }
    1363                this.pool = pool;
    1364                this.minIdle = minIdle;
    1365            }
    1366
    1367            /**
    1368             * {@inheritDoc}
    1369             */
    1370            public void run() {
    1371                boolean success = false;
    1372                try {
    1373                    if (pool.getNumIdle() < minIdle) {
    1374                        pool.addObject();
    1375                    }
    1376                    success = true;
    1377
    1378                } catch (Exception e) {
    1379                    cancel();
    1380
    1381                } finally {
    1382                    // detect other types of Throwable and cancel this Timer
    1383                    if (!success) {
    1384                        cancel();
    1385                    }
    1386                }
    1387            }
    1388
    1389            /**
    1390             * {@inheritDoc}
    1391             */
    1392            public String toString() {
    1393                final StringBuffer sb = new StringBuffer();
    1394                sb.append("ObjectPoolMinIdleTimerTask");
    1395                sb.append("{minIdle=").append(minIdle);
    1396                sb.append(", pool=").append(pool);
    1397                sb.append('}');
    1398                return sb.toString();
    1399            }
    1400        }
    1401
    1402        /**
    1403         * Timer task that adds objects to the pool until the number of idle
    1404         * instances for the given key reaches the configured minIdle.  Note that this is not the
    1405         * same as the pool's minIdle setting.
    1406         *
    1407         */
    1408        private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask {
    1409            /** Minimum number of idle instances.  Not the same as pool.getMinIdle(). */
    1410            private final int minIdle;
    1411
    1412            /** Key to ensure minIdle for */
    1413            private final Object key;
    1414
    1415            /** Keyed object pool */
    1416            private final KeyedObjectPool keyedPool;
    1417
    1418            /**
    1419             * Create a new KeyedObjecPoolMinIdleTimerTask.
    1420             *
    1421             * @param keyedPool keyed object pool
    1422             * @param key key to ensure minimum number of idle instances
    1423             * @param minIdle minimum number of idle instances
    1424             * @throws IllegalArgumentException if the key is null
    1425             */
    1426            KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, final Object key, final int minIdle) throws IllegalArgumentException {
    1427                if (keyedPool == null) {
    1428                    throw new IllegalArgumentException("keyedPool must not be null.");
    1429                }
    1430                this.keyedPool = keyedPool;
    1431                this.key = key;
    1432                this.minIdle = minIdle;
    1433            }
    1434
    1435            /**
    1436             * {@inheritDoc}
    1437             */
    1438            public void run() {
    1439                boolean success = false;
    1440                try {
    1441                    if (keyedPool.getNumIdle(key) < minIdle) {
    1442                        keyedPool.addObject(key);
    1443                    }
    1444                    success = true;
    1445
    1446                } catch (Exception e) {
    1447                    cancel();
    1448
    1449                } finally {
    1450                    // detect other types of Throwable and cancel this Timer
    1451                    if (!success) {
    1452                        cancel();
    1453                    }
    1454                }
    1455            }
    1456
    1457            /**
    1458             * {@inheritDoc}
    1459             */
    1460            public String toString() {
    1461                final StringBuffer sb = new StringBuffer();
    1462                sb.append("KeyedObjectPoolMinIdleTimerTask");
    1463                sb.append("{minIdle=").append(minIdle);
    1464                sb.append(", key=").append(key);
    1465                sb.append(", keyedPool=").append(keyedPool);
    1466                sb.append('}');
    1467                return sb.toString();
    1468            }
    1469        }
    1470
    1471        /**
    1472         * A synchronized (thread-safe) ObjectPool backed by the specified ObjectPool.
    1473         *
    1474         * <p><b>Note:</b>
    1475         * This should not be used on pool implementations that already provide proper synchronization
    1476         * such as the pools provided in the Commons Pool library. Wrapping a pool that
    1477         * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
    1478         * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
    1479         * </p>
    1480         */
    1481        private static class SynchronizedObjectPool implements ObjectPool {
    1482
    1483            /** Object whose monitor is used to synchronize methods on the wrapped pool. */
    1484            private final Object lock;
    1485
    1486            /** the underlying object pool */
    1487            private final ObjectPool pool;
    1488
    1489            /**
    1490             * Create a new SynchronizedObjectPool wrapping the given pool.
    1491             *
    1492             * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool.
    1493             * @throws IllegalArgumentException if the pool is null
    1494             */
    1495            SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException {
    1496                if (pool == null) {
    1497                    throw new IllegalArgumentException("pool must not be null.");
    1498                }
    1499                this.pool = pool;
    1500                lock = new Object();
    1501            }
    1502
    1503            /**
    1504             * {@inheritDoc}
    1505             */
    1506            public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
    1507                synchronized (lock) {
    1508                    return pool.borrowObject();
    1509                }
    1510            }
    1511
    1512            /**
    1513             * {@inheritDoc}
    1514             */
    1515            public void returnObject(final Object obj) {
    1516                synchronized (lock) {
    1517                    try {
    1518                        pool.returnObject(obj);
    1519                    } catch (Exception e) {
    1520                        // swallowed as of Pool 2
    1521                    }
    1522                }
    1523            }
    1524
    1525            /**
    1526             * {@inheritDoc}
    1527             */
    1528            public void invalidateObject(final Object obj) {
    1529                synchronized (lock) {
    1530                    try {
    1531                        pool.invalidateObject(obj);
    1532                    } catch (Exception e) {
    1533                        // swallowed as of Pool 2
    1534                    }
    1535                }
    1536            }
    1537
    1538            /**
    1539             * {@inheritDoc}
    1540             */
    1541            public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
    1542                synchronized (lock) {
    1543                    pool.addObject();
    1544                }
    1545            }
    1546
    1547            /**
    1548             * {@inheritDoc}
    1549             */
    1550            public int getNumIdle() throws UnsupportedOperationException {
    1551                synchronized (lock) {
    1552                    return pool.getNumIdle();
    1553                }
    1554            }
    1555
    1556            /**
    1557             * {@inheritDoc}
    1558             */
    1559            public int getNumActive() throws UnsupportedOperationException {
    1560                synchronized (lock) {
    1561                    return pool.getNumActive();
    1562                }
    1563            }
    1564
    1565            /**
    1566             * {@inheritDoc}
    1567             */
    1568            public void clear() throws Exception, UnsupportedOperationException {
    1569                synchronized (lock) {
    1570                    pool.clear();
    1571                }
    1572            }
    1573
    1574            /**
    1575             * {@inheritDoc}
    1576             */
    1577            public void close() {
    1578                try {
    1579                    synchronized (lock) {
    1580                        pool.close();
    1581                    }
    1582                } catch (Exception e) {
    1583                    // swallowed as of Pool 2
    1584                }
    1585            }
    1586
    1587            /**
    1588             * Sets the factory used by the pool.
    1589             *
    1590             * @param factory new PoolableObjectFactory
    1591             * @deprecated to be removed in pool 2.0
    1592             */
    1593            public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    1594                synchronized (lock) {
    1595                    pool.setFactory(factory);
    1596                }
    1597            }
    1598
    1599            /**
    1600             * {@inheritDoc}
    1601             */
    1602            public String toString() {
    1603                final StringBuffer sb = new StringBuffer();
    1604                sb.append("SynchronizedObjectPool");
    1605                sb.append("{pool=").append(pool);
    1606                sb.append('}');
    1607                return sb.toString();
    1608            }
    1609        }
    1610
    1611        /**
    1612         * A synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool.
    1613         *
    1614         * <p><b>Note:</b>
    1615         * This should not be used on pool implementations that already provide proper synchronization
    1616         * such as the pools provided in the Commons Pool library. Wrapping a pool that
    1617         * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
    1618         * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
    1619         * </p>
    1620         */
    1621        private static class SynchronizedKeyedObjectPool implements KeyedObjectPool {
    1622
    1623            /** Object whose monitor is used to synchronize methods on the wrapped pool. */
    1624            private final Object lock;
    1625
    1626            /** Underlying object pool */
    1627            private final KeyedObjectPool keyedPool;
    1628
    1629            /**
    1630             * Create a new SynchronizedKeyedObjectPool wrapping the given pool
    1631             *
    1632             * @param keyedPool KeyedObjectPool to wrap
    1633             * @throws IllegalArgumentException if keyedPool is null
    1634             */
    1635            SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
    1636                if (keyedPool == null) {
    1637                    throw new IllegalArgumentException("keyedPool must not be null.");
    1638                }
    1639                this.keyedPool = keyedPool;
    1640                lock = new Object();
    1641            }
    1642
    1643            /**
    1644             * {@inheritDoc}
    1645             */
    1646            public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
    1647                synchronized (lock) {
    1648                    return keyedPool.borrowObject(key);
    1649                }
    1650            }
    1651
    1652            /**
    1653             * {@inheritDoc}
    1654             */
    1655            public void returnObject(final Object key, final Object obj) {
    1656                synchronized (lock) {
    1657                    try {
    1658                        keyedPool.returnObject(key, obj);
    1659                    } catch (Exception e) {
    1660                        // swallowed
    1661                    }
    1662                }
    1663            }
    1664
    1665            /**
    1666             * {@inheritDoc}
    1667             */
    1668            public void invalidateObject(final Object key, final Object obj) {
    1669                synchronized (lock) {
    1670                    try {
    1671                        keyedPool.invalidateObject(key, obj);
    1672                    } catch (Exception e) {
    1673                        // swallowed as of Pool 2
    1674                    }
    1675                }
    1676            }
    1677
    1678            /**
    1679             * {@inheritDoc}
    1680             */
    1681            public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
    1682                synchronized (lock) {
    1683                    keyedPool.addObject(key);
    1684                }
    1685            }
    1686
    1687            /**
    1688             * {@inheritDoc}
    1689             */
    1690            public int getNumIdle(final Object key) throws UnsupportedOperationException {
    1691                synchronized (lock) {
    1692                    return keyedPool.getNumIdle(key);
    1693                }
    1694            }
    1695
    1696            /**
    1697             * {@inheritDoc}
    1698             */
    1699            public int getNumActive(final Object key) throws UnsupportedOperationException {
    1700                synchronized (lock) {
    1701                    return keyedPool.getNumActive(key);
    1702                }
    1703            }
    1704
    1705            /**
    1706             * {@inheritDoc}
    1707             */
    1708            public int getNumIdle() throws UnsupportedOperationException {
    1709                synchronized (lock) {
    1710                    return keyedPool.getNumIdle();
    1711                }
    1712            }
    1713
    1714            /**
    1715             * {@inheritDoc}
    1716             */
    1717            public int getNumActive() throws UnsupportedOperationException {
    1718                synchronized (lock) {
    1719                    return keyedPool.getNumActive();
    1720                }
    1721            }
    1722
    1723            /**
    1724             * {@inheritDoc}
    1725             */
    1726            public void clear() throws Exception, UnsupportedOperationException {
    1727                synchronized (lock) {
    1728                    keyedPool.clear();
    1729                }
    1730            }
    1731
    1732            /**
    1733             * {@inheritDoc}
    1734             */
    1735            public void clear(final Object key) throws Exception, UnsupportedOperationException {
    1736                synchronized (lock) {
    1737                    keyedPool.clear(key);
    1738                }
    1739            }
    1740
    1741            /**
    1742             * {@inheritDoc}
    1743             */
    1744            public void close() {
    1745                try {
    1746                    synchronized (lock) {
    1747                        keyedPool.close();
    1748                    }
    1749                } catch (Exception e) {
    1750                    // swallowed as of Pool 2
    1751                }
    1752            }
    1753
    1754            /**
    1755             * Sets the object factory used by the pool.
    1756             *
    1757             * @param factory KeyedPoolableObjectFactory used by the pool
    1758             * @deprecated to be removed in pool 2.0
    1759             */
    1760            public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    1761                synchronized (lock) {
    1762                    keyedPool.setFactory(factory);
    1763                }
    1764            }
    1765
    1766            /**
    1767             * {@inheritDoc}
    1768             */
    1769            public String toString() {
    1770                final StringBuffer sb = new StringBuffer();
    1771                sb.append("SynchronizedKeyedObjectPool");
    1772                sb.append("{keyedPool=").append(keyedPool);
    1773                sb.append('}');
    1774                return sb.toString();
    1775            }
    1776        }
    1777
    1778        /**
    1779         * A fully synchronized PoolableObjectFactory that wraps a PoolableObjectFactory and synchronizes
    1780         * access to the wrapped factory methods.
    1781         *
    1782         * <p><b>Note:</b>
    1783         * This should not be used on pool implementations that already provide proper synchronization
    1784         * such as the pools provided in the Commons Pool library. </p>
    1785         */
    1786        private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory {
    1787            /** Synchronization lock */
    1788            private final Object lock;
    1789
    1790            /** Wrapped factory */
    1791            private final PoolableObjectFactory factory;
    1792
    1793            /**
    1794             * Create a SynchronizedPoolableObjectFactory wrapping the given factory.
    1795             *
    1796             * @param factory underlying factory to wrap
    1797             * @throws IllegalArgumentException if the factory is null
    1798             */
    1799            SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException {
    1800                if (factory == null) {
    1801                    throw new IllegalArgumentException("factory must not be null.");
    1802                }
    1803                this.factory = factory;
    1804                lock = new Object();
    1805            }
    1806
    1807            /**
    1808             * {@inheritDoc}
    1809             */
    1810            public Object makeObject() throws Exception {
    1811                synchronized (lock) {
    1812                    return factory.makeObject();
    1813                }
    1814            }
    1815
    1816            /**
    1817             * {@inheritDoc}
    1818             */
    1819            public void destroyObject(final Object obj) throws Exception {
    1820                synchronized (lock) {
    1821                    factory.destroyObject(obj);
    1822                }
    1823            }
    1824
    1825            /**
    1826             * {@inheritDoc}
    1827             */
    1828            public boolean validateObject(final Object obj) {
    1829                synchronized (lock) {
    1830                    return factory.validateObject(obj);
    1831                }
    1832            }
    1833
    1834            /**
    1835             * {@inheritDoc}
    1836             */
    1837            public void activateObject(final Object obj) throws Exception {
    1838                synchronized (lock) {
    1839                    factory.activateObject(obj);
    1840                }
    1841            }
    1842
    1843            /**
    1844             * {@inheritDoc}
    1845             */
    1846            public void passivateObject(final Object obj) throws Exception {
    1847                synchronized (lock) {
    1848                    factory.passivateObject(obj);
    1849                }
    1850            }
    1851
    1852            /**
    1853             * {@inheritDoc}
    1854             */
    1855            public String toString() {
    1856                final StringBuffer sb = new StringBuffer();
    1857                sb.append("SynchronizedPoolableObjectFactory");
    1858                sb.append("{factory=").append(factory);
    1859                sb.append('}');
    1860                return sb.toString();
    1861            }
    1862        }
    1863
    1864        /**
    1865         * A fully synchronized KeyedPoolableObjectFactory that wraps a KeyedPoolableObjectFactory and synchronizes
    1866         * access to the wrapped factory methods.
    1867         *
    1868         * <p><b>Note:</b>
    1869         * This should not be used on pool implementations that already provide proper synchronization
    1870         * such as the pools provided in the Commons Pool library. </p>
    1871         */
    1872        private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory {
    1873            /** Synchronization lock */
    1874            private final Object lock;
    1875
    1876            /** Wrapped factory */
    1877            private final KeyedPoolableObjectFactory keyedFactory;
    1878
    1879            /**
    1880             * Create a SynchronizedKeyedPoolableObjectFactory wrapping the given factory.
    1881             *
    1882             * @param keyedFactory underlying factory to wrap
    1883             * @throws IllegalArgumentException if the factory is null
    1884             */
    1885            SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
    1886                if (keyedFactory == null) {
    1887                    throw new IllegalArgumentException("keyedFactory must not be null.");
    1888                }
    1889                this.keyedFactory = keyedFactory;
    1890                lock = new Object();
    1891            }
    1892
    1893            /**
    1894             * {@inheritDoc}
    1895             */
    1896            public Object makeObject(final Object key) throws Exception {
    1897                synchronized (lock) {
    1898                    return keyedFactory.makeObject(key);
    1899                }
    1900            }
    1901
    1902            /**
    1903             * {@inheritDoc}
    1904             */
    1905            public void destroyObject(final Object key, final Object obj) throws Exception {
    1906                synchronized (lock) {
    1907                    keyedFactory.destroyObject(key, obj);
    1908                }
    1909            }
    1910
    1911            /**
    1912             * {@inheritDoc}
    1913             */
    1914            public boolean validateObject(final Object key, final Object obj) {
    1915                synchronized (lock) {
    1916                    return keyedFactory.validateObject(key, obj);
    1917                }
    1918            }
    1919
    1920            /**
    1921             * {@inheritDoc}
    1922             */
    1923            public void activateObject(final Object key, final Object obj) throws Exception {
    1924                synchronized (lock) {
    1925                    keyedFactory.activateObject(key, obj);
    1926                }
    1927            }
    1928
    1929            /**
    1930             * {@inheritDoc}
    1931             */
    1932            public void passivateObject(final Object key, final Object obj) throws Exception {
    1933                synchronized (lock) {
    1934                    keyedFactory.passivateObject(key, obj);
    1935                }
    1936            }
    1937
    1938            /**
    1939             * {@inheritDoc}
    1940             */
    1941            public String toString() {
    1942                final StringBuffer sb = new StringBuffer();
    1943                sb.append("SynchronizedKeyedPoolableObjectFactory");
    1944                sb.append("{keyedFactory=").append(keyedFactory);
    1945                sb.append('}');
    1946                return sb.toString();
    1947            }
    1948        }
    1949
    1950        /**
    1951         * Encapsulate the logic for when the next poolable object should be discarded.
    1952         * Each time update is called, the next time to shrink is recomputed, based on
    1953         * the float factor, number of idle instances in the pool and high water mark.
    1954         * Float factor is assumed to be between 0 and 1.  Values closer to 1 cause
    1955         * less frequent erosion events.  Erosion event timing also depends on numIdle.
    1956         * When this value is relatively high (close to previously established high water
    1957         * mark), erosion occurs more frequently.
    1958         */
    1959        private static class ErodingFactor {
    1960            /** Determines frequency of "erosion" events */
    1961            private final float factor;
    1962
    1963            /** Time of next shrink event */
    1964            private transient volatile long nextShrink;
    1965
    1966            /** High water mark - largest numIdle encountered */
    1967            private transient volatile int idleHighWaterMark;
    1968
    1969            /**
    1970             * Create a new ErodingFactor with the given erosion factor.
    1971             *
    1972             * @param factor erosion factor
    1973             */
    1974            public ErodingFactor(final float factor) {
    1975                this.factor = factor;
    1976                nextShrink = System.currentTimeMillis() + (long)(900000 * factor); // now + 15 min * factor
    1977                idleHighWaterMark = 1;
    1978            }
    1979
    1980            /**
    1981             * Updates internal state based on numIdle and the current time.
    1982             *
    1983             * @param numIdle number of idle elements in the pool
    1984             */
    1985            public void update(final int numIdle) {
    1986                update(System.currentTimeMillis(), numIdle);
    1987            }
    1988
    1989            /**
    1990             * Updates internal state using the supplied time and numIdle.
    1991             *
    1992             * @param now current time
    1993             * @param numIdle number of idle elements in the pool
    1994             */
    1995            public void update(final long now, final int numIdle) {
    1996                final int idle = Math.max(0, numIdle);
    1997                idleHighWaterMark = Math.max(idle, idleHighWaterMark);
    1998                final float maxInterval = 15f;
    1999                final float minutes = maxInterval + ((1f-maxInterval)/idleHighWaterMark) * idle;
    2000                nextShrink = now + (long)(minutes * 60000f * factor);
    2001            }
    2002
    2003            /**
    2004             * Returns the time of the next erosion event.
    2005             *
    2006             * @return next shrink time
    2007             */
    2008            public long getNextShrink() {
    2009                return nextShrink;
    2010            }
    2011
    2012            /**
    2013             * {@inheritDoc}
    2014             */
    2015            public String toString() {
    2016                return "ErodingFactor{" +
    2017                        "factor=" + factor +
    2018                        ", idleHighWaterMark=" + idleHighWaterMark +
    2019                        '}';
    2020            }
    2021        }
    2022
    2023        /**
    2024         * Decorates an object pool, adding "eroding" behavior.  Based on the
    2025         * configured {@link #factor erosion factor}, objects returning to the pool
    2026         * may be invalidated instead of being added to idle capacity.
    2027         *
    2028         */
    2029        private static class ErodingObjectPool implements ObjectPool {
    2030            /** Underlying object pool */
    2031            private final ObjectPool pool;
    2032
    2033            /** Erosion factor */
    2034            private final ErodingFactor factor;
    2035
    2036            /**
    2037             * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor.
    2038             *
    2039             * @param pool underlying pool
    2040             * @param factor erosion factor - determines the frequency of erosion events
    2041             * @see #factor
    2042             */
    2043            public ErodingObjectPool(final ObjectPool pool, final float factor) {
    2044                this.pool = pool;
    2045                this.factor = new ErodingFactor(factor);
    2046            }
    2047
    2048            /**
    2049             * {@inheritDoc}
    2050             */
    2051            public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
    2052                return pool.borrowObject();
    2053            }
    2054
    2055            /**
    2056             * Returns obj to the pool, unless erosion is triggered, in which
    2057             * case obj is invalidated.  Erosion is triggered when there are idle instances in
    2058             * the pool and more than the {@link #factor erosion factor}-determined time has elapsed
    2059             * since the last returnObject activation.
    2060             *
    2061             * @param obj object to return or invalidate
    2062             * @see #factor
    2063             */
    2064            public void returnObject(final Object obj) {
    2065                boolean discard = false;
    2066                final long now = System.currentTimeMillis();
    2067                synchronized (pool) {
    2068                    if (factor.getNextShrink() < now) { // XXX: Pool 3: move test out of sync block
    2069                        final int numIdle = pool.getNumIdle();
    2070                        if (numIdle > 0) {
    2071                            discard = true;
    2072                        }
    2073
    2074                        factor.update(now, numIdle);
    2075                    }
    2076                }
    2077                try {
    2078                    if (discard) {
    2079                        pool.invalidateObject(obj);
    2080                    } else {
    2081                        pool.returnObject(obj);
    2082                    }
    2083                } catch (Exception e) {
    2084                    // swallowed
    2085                }
    2086            }
    2087
    2088            /**
    2089             * {@inheritDoc}
    2090             */
    2091            public void invalidateObject(final Object obj) {
    2092                try {
    2093                    pool.invalidateObject(obj);
    2094                } catch (Exception e) {
    2095                    // swallowed
    2096                }
    2097            }
    2098
    2099            /**
    2100             * {@inheritDoc}
    2101             */
    2102            public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
    2103                pool.addObject();
    2104            }
    2105
    2106            /**
    2107             * {@inheritDoc}
    2108             */
    2109            public int getNumIdle() throws UnsupportedOperationException {
    2110                return pool.getNumIdle();
    2111            }
    2112
    2113            /**
    2114             * {@inheritDoc}
    2115             */
    2116            public int getNumActive() throws UnsupportedOperationException {
    2117                return pool.getNumActive();
    2118            }
    2119
    2120            /**
    2121             * {@inheritDoc}
    2122             */
    2123            public void clear() throws Exception, UnsupportedOperationException {
    2124                pool.clear();
    2125            }
    2126
    2127            /**
    2128             * {@inheritDoc}
    2129             */
    2130            public void close() {
    2131                try {
    2132                    pool.close();
    2133                } catch (Exception e) {
    2134                    // swallowed
    2135                }
    2136            }
    2137
    2138            /**
    2139             * {@inheritDoc}
    2140             * @deprecated to be removed in pool 2.0
    2141             */
    2142            public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    2143                pool.setFactory(factory);
    2144            }
    2145
    2146            /**
    2147             * {@inheritDoc}
    2148             */
    2149            public String toString() {
    2150                return "ErodingObjectPool{" +
    2151                        "factor=" + factor +
    2152                        ", pool=" + pool +
    2153                        '}';
    2154            }
    2155        }
    2156
    2157        /**
    2158         * Decorates a keyed object pool, adding "eroding" behavior.  Based on the
    2159         * configured {@link #factor erosion factor}, objects returning to the pool
    2160         * may be invalidated instead of being added to idle capacity.
    2161         *
    2162         */
    2163        private static class ErodingKeyedObjectPool implements KeyedObjectPool {
    2164            /** Underlying pool */
    2165            private final KeyedObjectPool keyedPool;
    2166
    2167            /** Erosion factor */
    2168            private final ErodingFactor erodingFactor;
    2169
    2170            /**
    2171             * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor.
    2172             *
    2173             * @param keyedPool underlying pool
    2174             * @param factor erosion factor - determines the frequency of erosion events
    2175             * @see #erodingFactor
    2176             */
    2177            public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) {
    2178                this(keyedPool, new ErodingFactor(factor));
    2179            }
    2180
    2181            /**
    2182             * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor.
    2183             *
    2184             * @param keyedPool underlying pool - must not be null
    2185             * @param erodingFactor erosion factor - determines the frequency of erosion events
    2186             * @see #factor
    2187             */
    2188            protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final ErodingFactor erodingFactor) {
    2189                if (keyedPool == null) {
    2190                    throw new IllegalArgumentException("keyedPool must not be null.");
    2191                }
    2192                this.keyedPool = keyedPool;
    2193                this.erodingFactor = erodingFactor;
    2194            }
    2195
    2196            /**
    2197             * {@inheritDoc}
    2198             */
    2199            public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
    2200                return keyedPool.borrowObject(key);
    2201            }
    2202
    2203            /**
    2204             * Returns obj to the pool, unless erosion is triggered, in which
    2205             * case obj is invalidated.  Erosion is triggered when there are idle instances in
    2206             * the pool associated with the given key and more than the configured {@link #erodingFactor erosion factor}
    2207             * time has elapsed since the last returnObject activation.
    2208             *
    2209             * @param obj object to return or invalidate
    2210             * @param key key
    2211             * @see #erodingFactor
    2212             */
    2213            public void returnObject(final Object key, final Object obj) throws Exception {
    2214                boolean discard = false;
    2215                final long now = System.currentTimeMillis();
    2216                final ErodingFactor factor = getErodingFactor(key);
    2217                synchronized (keyedPool) {
    2218                    if (factor.getNextShrink() < now) {
    2219                        final int numIdle = numIdle(key);
    2220                        if (numIdle > 0) {
    2221                            discard = true;
    2222                        }
    2223
    2224                        factor.update(now, numIdle);
    2225                    }
    2226                }
    2227                try {
    2228                    if (discard) {
    2229                        keyedPool.invalidateObject(key, obj);
    2230                    } else {
    2231                        keyedPool.returnObject(key, obj);
    2232                    }
    2233                } catch (Exception e) {
    2234                    // swallowed
    2235                }
    2236            }
    2237
    2238            /**
    2239             * {@inheritDoc}
    2240             */
    2241            protected int numIdle(final Object key) {
    2242                return getKeyedPool().getNumIdle();
    2243            }
    2244
    2245            /**
    2246             * Returns the eroding factor for the given key
    2247             * @param key key
    2248             * @return eroding factor for the given keyed pool
    2249             */
    2250            protected ErodingFactor getErodingFactor(final Object key) {
    2251                return erodingFactor;
    2252            }
    2253
    2254            /**
    2255             * {@inheritDoc}
    2256             */
    2257            public void invalidateObject(final Object key, final Object obj) {
    2258                try {
    2259                    keyedPool.invalidateObject(key, obj);
    2260                } catch (Exception e) {
    2261                    // swallowed
    2262                }
    2263            }
    2264
    2265            /**
    2266             * {@inheritDoc}
    2267             */
    2268            public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
    2269                keyedPool.addObject(key);
    2270            }
    2271
    2272            /**
    2273             * {@inheritDoc}
    2274             */
    2275            public int getNumIdle() throws UnsupportedOperationException {
    2276                return keyedPool.getNumIdle();
    2277            }
    2278
    2279            /**
    2280             * {@inheritDoc}
    2281             */
    2282            public int getNumIdle(final Object key) throws UnsupportedOperationException {
    2283                return keyedPool.getNumIdle(key);
    2284            }
    2285
    2286            /**
    2287             * {@inheritDoc}
    2288             */
    2289            public int getNumActive() throws UnsupportedOperationException {
    2290                return keyedPool.getNumActive();
    2291            }
    2292
    2293            /**
    2294             * {@inheritDoc}
    2295             */
    2296            public int getNumActive(final Object key) throws UnsupportedOperationException {
    2297                return keyedPool.getNumActive(key);
    2298            }
    2299
    2300            /**
    2301             * {@inheritDoc}
    2302             */
    2303            public void clear() throws Exception, UnsupportedOperationException {
    2304                keyedPool.clear();
    2305            }
    2306
    2307            /**
    2308             * {@inheritDoc}
    2309             */
    2310            public void clear(final Object key) throws Exception, UnsupportedOperationException {
    2311                keyedPool.clear(key);
    2312            }
    2313
    2314            /**
    2315             * {@inheritDoc}
    2316             */
    2317            public void close() {
    2318                try {
    2319                    keyedPool.close();
    2320                } catch (Exception e) {
    2321                    // swallowed
    2322                }
    2323            }
    2324
    2325            /**
    2326             * {@inheritDoc}
    2327             * @deprecated to be removed in pool 2.0
    2328             */
    2329            public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
    2330                keyedPool.setFactory(factory);
    2331            }
    2332
    2333            /**
    2334             * Returns the underlying pool
    2335             *
    2336             * @return the keyed pool that this ErodingKeyedObjectPool wraps
    2337             */
    2338            protected KeyedObjectPool getKeyedPool() {
    2339                return keyedPool;
    2340            }
    2341
    2342            /**
    2343             * {@inheritDoc}
    2344             */
    2345            public String toString() {
    2346                return "ErodingKeyedObjectPool{" +
    2347                        "erodingFactor=" + erodingFactor +
    2348                        ", keyedPool=" + keyedPool +
    2349                        '}';
    2350            }
    2351        }
    2352
    2353        /**
    2354         * Extends ErodingKeyedObjectPool to allow erosion to take place on a per-key
    2355         * basis.  Timing of erosion events is tracked separately for separate keyed pools.
    2356         */
    2357        private static class ErodingPerKeyKeyedObjectPool extends ErodingKeyedObjectPool {
    2358            /** Erosion factor - same for all pools */
    2359            private final float factor;
    2360
    2361            /** Map of ErodingFactor instances keyed on pool keys */
    2362            private final Map factors = Collections.synchronizedMap(new HashMap());
    2363
    2364            /**
    2365             * Create a new ErordingPerKeyKeyedObjectPool decorating the given keyed pool with
    2366             * the specified erosion factor.
    2367             * @param keyedPool underlying keyed pool
    2368             * @param factor erosion factor
    2369             */
    2370            public ErodingPerKeyKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) {
    2371                super(keyedPool, null);
    2372                this.factor = factor;
    2373            }
    2374
    2375            /**
    2376             * {@inheritDoc}
    2377             */
    2378            protected int numIdle(final Object key) {
    2379                return getKeyedPool().getNumIdle(key);
    2380            }
    2381
    2382            /**
    2383             * {@inheritDoc}
    2384             */
    2385            protected ErodingFactor getErodingFactor(final Object key) {
    2386                ErodingFactor factor = (ErodingFactor)factors.get(key);
    2387                // this may result in two ErodingFactors being created for a key
    2388                // since they are small and cheap this is okay.
    2389                if (factor == null) {
    2390                    factor = new ErodingFactor(this.factor);
    2391                    factors.put(key, factor);
    2392                }
    2393                return factor;
    2394            }
    2395
    2396            /**
    2397             * {@inheritDoc}
    2398             */
    2399            public String toString() {
    2400                return "ErodingPerKeyKeyedObjectPool{" +
    2401                        "factor=" + factor +
    2402                        ", keyedPool=" + getKeyedPool() +
    2403                        '}';
    2404            }
    2405        }
    2406    }