    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 */
    017package org.apache.commons.pool2;
    018
    019import java.util.Collection;
    020import java.util.Collections;
    021import java.util.HashMap;
    022import java.util.Iterator;
    023import java.util.Map;
    024import java.util.NoSuchElementException;
    025import java.util.Timer;
    026import java.util.TimerTask;
    027import java.util.concurrent.locks.ReentrantReadWriteLock;
    028import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
    029import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
    030
    031/**
    032 * This class consists exclusively of static methods that operate on or return
    033 * ObjectPool or KeyedObjectPool related interfaces.
    034 *
    035 * @since 2.0
    036 */
    037public final class PoolUtils {
    038
    039    private static final String MSG_FACTOR_NEGATIVE = "factor must be positive.";
    040    private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
    041    static final String MSG_NULL_KEY = "key must not be null.";
    042    private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
    043    static final String MSG_NULL_KEYS = "keys must not be null.";
    044    private static final String MSG_NULL_POOL = "pool must not be null.";
    045
    046    /**
    047     * Timer used to periodically check pools idle object count. Because a
    048     * {@link Timer} creates a {@link Thread}, an IODH is used.
    049     */
    050    static class TimerHolder {
    051        static final Timer MIN_IDLE_TIMER = new Timer(true);
    052    }
    053
    054    /**
    055     * PoolUtils instances should NOT be constructed in standard programming.
    056     * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
    057     * This constructor is public to permit tools that require a JavaBean
    058     * instance to operate.
    059     */
    060    public PoolUtils() {
    061    }
    062
    063    /**
    064     * Should the supplied Throwable be re-thrown (eg if it is an instance of
    065     * one of the Throwables that should never be swallowed). Used by the pool
    066     * error handling for operations that throw exceptions that normally need to
    067     * be ignored.
    068     *
    069     * @param t
    070     *            The Throwable to check
    071     * @throws ThreadDeath
    072     *             if that is passed in
    073     * @throws VirtualMachineError
    074     *             if that is passed in
    075     */
    076    public static void checkRethrow(final Throwable t) {
    077        if (t instanceof ThreadDeath) {
    078            throw (ThreadDeath) t;
    079        }
    080        if (t instanceof VirtualMachineError) {
    081            throw (VirtualMachineError) t;
    082        }
    083        // All other instances of Throwable will be silently swallowed
    084    }
    085
    086    /**
    087     * Periodically check the idle object count for the pool. At most one idle
    088     * object will be added per period. If there is an exception when calling
    089     * {@link ObjectPool#addObject()} then no more checks will be performed.
    090     *
    091     * @param pool
    092     *            the pool to check periodically.
    093     * @param minIdle
    094     *            if the {@link ObjectPool#getNumIdle()} is less than this then
    095     *            add an idle object.
    096     * @param period
    097     *            the frequency to check the number of idle objects in a pool,
    098     *            see {@link Timer#schedule(TimerTask, long, long)}.
    099     * @param <T> the type of objects in the pool
    100     * @return the {@link TimerTask} that will periodically check the pools idle
    101     *         object count.
    102     * @throws IllegalArgumentException
    103     *             when {@code pool} is {@code null} or when {@code minIdle} is
    104     *             negative or when {@code period} isn't valid for
    105     *             {@link Timer#schedule(TimerTask, long, long)}
    106     */
    107    public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool,
    108            final int minIdle, final long period)
    109            throws IllegalArgumentException {
    110        if (pool == null) {
    111            throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
    112        }
    113        if (minIdle < 0) {
    114            throw new IllegalArgumentException(MSG_MIN_IDLE);
    115        }
    116        final TimerTask task = new ObjectPoolMinIdleTimerTask<>(pool, minIdle);
    117        getMinIdleTimer().schedule(task, 0L, period);
    118        return task;
    119    }
    120
    121    /**
    122     * Periodically check the idle object count for the key in the keyedPool. At
    123     * most one idle object will be added per period. If there is an exception
    124     * when calling {@link KeyedObjectPool#addObject(Object)} then no more
    125     * checks for that key will be performed.
    126     *
    127     * @param keyedPool
    128     *            the keyedPool to check periodically.
    129     * @param key
    130     *            the key to check the idle count of.
    131     * @param minIdle
    132     *            if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
    133     *            this then add an idle object.
    134     * @param period
    135     *            the frequency to check the number of idle objects in a
    136     *            keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
    137     * @param <K> the type of the pool key
    138     * @param <V> the type of pool entries
    139     * @return the {@link TimerTask} that will periodically check the pools idle
    140     *         object count.
    141     * @throws IllegalArgumentException
    142     *             when {@code keyedPool}, {@code key} is {@code null} or
    143     *             when {@code minIdle} is negative or when {@code period} isn't
    144     *             valid for {@link Timer#schedule(TimerTask, long, long)}.
    145     */
    146    public static <K, V> TimerTask checkMinIdle(
    147            final KeyedObjectPool<K, V> keyedPool, final K key,
    148            final int minIdle, final long period)
    149            throws IllegalArgumentException {
    150        if (keyedPool == null) {
    151            throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
    152        }
    153        if (key == null) {
    154            throw new IllegalArgumentException(MSG_NULL_KEY);
    155        }
    156        if (minIdle < 0) {
    157            throw new IllegalArgumentException(MSG_MIN_IDLE);
    158        }
    159        final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<>(
    160                keyedPool, key, minIdle);
    161        getMinIdleTimer().schedule(task, 0L, period);
    162        return task;
    163    }
    164
    165    /**
    166     * Periodically check the idle object count for each key in the
    167     * {@code Collection keys} in the keyedPool. At most one idle object will be
    168     * added per period.
    169     *
    170     * @param keyedPool
    171     *            the keyedPool to check periodically.
    172     * @param keys
    173     *            a collection of keys to check the idle object count.
    174     * @param minIdle
    175     *            if the {@link KeyedObjectPool#getNumIdle(Object)} is less than
    176     *            this then add an idle object.
    177     * @param period
    178     *            the frequency to check the number of idle objects in a
    179     *            keyedPool, see {@link Timer#schedule(TimerTask, long, long)}.
    180     * @param <K> the type of the pool key
    181     * @param <V> the type of pool entries
    182     * @return a {@link Map} of key and {@link TimerTask} pairs that will
    183     *         periodically check the pools idle object count.
    184     * @throws IllegalArgumentException
    185     *             when {@code keyedPool}, {@code keys}, or any of the values in
    186     *             the collection is {@code null} or when {@code minIdle} is
    187     *             negative or when {@code period} isn't valid for
    188     *             {@link Timer#schedule(TimerTask, long, long)}.
    189     * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
    190     */
    191    public static <K, V> Map<K, TimerTask> checkMinIdle(
    192            final KeyedObjectPool<K, V> keyedPool, final Collection<K> keys,
    193            final int minIdle, final long period)
    194            throws IllegalArgumentException {
    195        if (keys == null) {
    196            throw new IllegalArgumentException(MSG_NULL_KEYS);
    197        }
    198        final Map<K, TimerTask> tasks = new HashMap<>(keys.size());
    199        final Iterator<K> iter = keys.iterator();
    200        while (iter.hasNext()) {
    201            final K key = iter.next();
    202            final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
    203            tasks.put(key, task);
    204        }
    205        return tasks;
    206    }
    207
    208    /**
    209     * Calls {@link ObjectPool#addObject()} on {@code pool} {@code count} number
    210     * of times.
    211     *
    212     * @param pool
    213     *            the pool to prefill.
    214     * @param count
    215     *            the number of idle objects to add.
    216     * @param <T> the type of objects in the pool
    217     * @throws Exception
    218     *             when {@link ObjectPool#addObject()} fails.
    219     * @throws IllegalArgumentException
    220     *             when {@code pool} is {@code null}.
    221     * @deprecated Use {@link ObjectPool#addObjects(int)}.
    222     */
    223    @Deprecated
    224    public static <T> void prefill(final ObjectPool<T> pool, final int count)
    225            throws Exception, IllegalArgumentException {
    226        if (pool == null) {
    227            throw new IllegalArgumentException(MSG_NULL_POOL);
    228        }
    229        pool.addObjects(count);
    230    }
    231
    232    /**
    233     * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with
    234     * {@code key} {@code count} number of times.
    235     *
    236     * @param keyedPool
    237     *            the keyedPool to prefill.
    238     * @param key
    239     *            the key to add objects for.
    240     * @param count
    241     *            the number of idle objects to add for {@code key}.
    242     * @param <K> the type of the pool key
    243     * @param <V> the type of pool entries
    244     * @throws Exception
    245     *             when {@link KeyedObjectPool#addObject(Object)} fails.
    246     * @throws IllegalArgumentException
    247     *             when {@code keyedPool} or {@code key} is {@code null}.
    248     * @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}.
    249     */
    250    @Deprecated
    251    public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
    252            final K key, final int count) throws Exception,
    253            IllegalArgumentException {
    254        if (keyedPool == null) {
    255            throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
    256        }
    257        keyedPool.addObjects(key, count);
    258    }
    259
    260    /**
    261     * Calls {@link KeyedObjectPool#addObject(Object)} on {@code keyedPool} with
    262     * each key in {@code keys} for {@code count} number of times. This has
    263     * the same effect as calling {@link #prefill(KeyedObjectPool, Object, int)}
    264     * for each key in the {@code keys} collection.
    265     *
    266     * @param keyedPool
    267     *            the keyedPool to prefill.
    268     * @param keys
    269     *            {@link Collection} of keys to add objects for.
    270     * @param count
    271     *            the number of idle objects to add for each {@code key}.
    272     * @param <K> the type of the pool key
    273     * @param <V> the type of pool entries
    274     * @throws Exception
    275     *             when {@link KeyedObjectPool#addObject(Object)} fails.
    276     * @throws IllegalArgumentException
    277     *             when {@code keyedPool}, {@code keys}, or any value in
    278     *             {@code keys} is {@code null}.
    279     * @see #prefill(KeyedObjectPool, Object, int)
    280     * @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}.
    281     */
    282    @Deprecated
    283    public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
    284            final Collection<K> keys, final int count) throws Exception,
    285            IllegalArgumentException {
    286        if (keys == null) {
    287            throw new IllegalArgumentException(MSG_NULL_KEYS);
    288        }
    289        keyedPool.addObjects(keys, count);
    290    }
    291
    292    /**
    293     * Returns a synchronized (thread-safe) ObjectPool backed by the specified
    294     * ObjectPool.
    295     * <p>
    296     * <b>Note:</b> This should not be used on pool implementations that already
    297     * provide proper synchronization such as the pools provided in the Commons
    298     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
    299     * objects to be returned before allowing another one to be borrowed with
    300     * another layer of synchronization will cause liveliness issues or a
    301     * deadlock.
    302     * </p>
    303     *
    304     * @param pool
    305     *            the ObjectPool to be "wrapped" in a synchronized ObjectPool.
    306     * @param <T> the type of objects in the pool
    307     * @throws IllegalArgumentException
    308     *             when {@code pool} is {@code null}.
    309     * @return a synchronized view of the specified ObjectPool.
    310     */
    311    public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
    312        if (pool == null) {
    313            throw new IllegalArgumentException(MSG_NULL_POOL);
    314        }
    315        /*
    316         * assert !(pool instanceof GenericObjectPool) :
    317         * "GenericObjectPool is already thread-safe"; assert !(pool instanceof
    318         * SoftReferenceObjectPool) :
    319         * "SoftReferenceObjectPool is already thread-safe"; assert !(pool
    320         * instanceof StackObjectPool) :
    321         * "StackObjectPool is already thread-safe"; assert
    322         * !"org.apache.commons.pool.composite.CompositeObjectPool"
    323         * .equals(pool.getClass().getName()) :
    324         * "CompositeObjectPools are already thread-safe";
    325         */
    326        return new SynchronizedObjectPool<>(pool);
    327    }
    328
    329    /**
    330     * Returns a synchronized (thread-safe) KeyedObjectPool backed by the
    331     * specified KeyedObjectPool.
    332     * <p>
    333     * <b>Note:</b> This should not be used on pool implementations that already
    334     * provide proper synchronization such as the pools provided in the Commons
    335     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
    336     * objects to be returned before allowing another one to be borrowed with
    337     * another layer of synchronization will cause liveliness issues or a
    338     * deadlock.
    339     * </p>
    340     *
    341     * @param keyedPool
    342     *            the KeyedObjectPool to be "wrapped" in a synchronized
    343     *            KeyedObjectPool.
    344     * @param <K> the type of the pool key
    345     * @param <V> the type of pool entries
    346     * @return a synchronized view of the specified KeyedObjectPool.
    347     */
    348    public static <K, V> KeyedObjectPool<K, V> synchronizedPool(
    349            final KeyedObjectPool<K, V> keyedPool) {
    350        /*
    351         * assert !(keyedPool instanceof GenericKeyedObjectPool) :
    352         * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool
    353         * instanceof StackKeyedObjectPool) :
    354         * "StackKeyedObjectPool is already thread-safe"; assert
    355         * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool"
    356         * .equals(keyedPool.getClass().getName()) :
    357         * "CompositeKeyedObjectPools are already thread-safe";
    358         */
    359        return new SynchronizedKeyedObjectPool<>(keyedPool);
    360    }
    361
    362    /**
    363     * Returns a synchronized (thread-safe) PooledObjectFactory backed by the
    364     * specified PooledObjectFactory.
    365     *
    366     * @param factory
    367     *            the PooledObjectFactory to be "wrapped" in a synchronized
    368     *            PooledObjectFactory.
    369     * @param <T> the type of objects in the pool
    370     * @return a synchronized view of the specified PooledObjectFactory.
    371     */
    372    public static <T> PooledObjectFactory<T> synchronizedPooledFactory(
    373            final PooledObjectFactory<T> factory) {
    374        return new SynchronizedPooledObjectFactory<>(factory);
    375    }
    376
    377    /**
    378     * Returns a synchronized (thread-safe) KeyedPooledObjectFactory backed by
    379     * the specified KeyedPoolableObjectFactory.
    380     *
    381     * @param keyedFactory
    382     *            the KeyedPooledObjectFactory to be "wrapped" in a
    383     *            synchronized KeyedPooledObjectFactory.
    384     * @param <K> the type of the pool key
    385     * @param <V> the type of pool entries
    386     * @return a synchronized view of the specified KeyedPooledObjectFactory.
    387     */
    388    public static <K, V> KeyedPooledObjectFactory<K, V> synchronizedKeyedPooledFactory(
    389            final KeyedPooledObjectFactory<K, V> keyedFactory) {
    390        return new SynchronizedKeyedPooledObjectFactory<>(keyedFactory);
    391    }
    392
    393    /**
    394     * Returns a pool that adaptively decreases its size when idle objects are
    395     * no longer needed. This is intended as an always thread-safe alternative
    396     * to using an idle object evictor provided by many pool implementations.
    397     * This is also an effective way to shrink FIFO ordered pools that
    398     * experience load spikes.
    399     *
    400     * @param pool
    401     *            the ObjectPool to be decorated so it shrinks its idle count
    402     *            when possible.
    403     * @param <T> the type of objects in the pool
    404     * @throws IllegalArgumentException
    405     *             when {@code pool} is {@code null}.
    406     * @return a pool that adaptively decreases its size when idle objects are
    407     *         no longer needed.
    408     * @see #erodingPool(ObjectPool, float)
    409     */
    410    public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
    411        return erodingPool(pool, 1f);
    412    }
    413
    414    /**
    415     * Returns a pool that adaptively decreases its size when idle objects are
    416     * no longer needed. This is intended as an always thread-safe alternative
    417     * to using an idle object evictor provided by many pool implementations.
    418     * This is also an effective way to shrink FIFO ordered pools that
    419     * experience load spikes.
    420     * <p>
    421     * The factor parameter provides a mechanism to tweak the rate at which the
    422     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
    423     * try to shrink its size more often. Values greater than 1 cause the pool
    424     * to less frequently try to shrink its size.
    425     * </p>
    426     *
    427     * @param pool
    428     *            the ObjectPool to be decorated so it shrinks its idle count
    429     *            when possible.
    430     * @param factor
    431     *            a positive value to scale the rate at which the pool tries to
    432     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
    433     *            shrinks more aggressively. If 1 &lt; factor then the pool
    434     *            shrinks less aggressively.
    435     * @param <T> the type of objects in the pool
    436     * @throws IllegalArgumentException
    437     *             when {@code pool} is {@code null} or when {@code factor} is
    438     *             not positive.
    439     * @return a pool that adaptively decreases its size when idle objects are
    440     *         no longer needed.
    441     * @see #erodingPool(ObjectPool)
    442     */
    443    public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool,
    444            final float factor) {
    445        if (pool == null) {
    446            throw new IllegalArgumentException(MSG_NULL_POOL);
    447        }
    448        if (factor <= 0f) {
    449            throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
    450        }
    451        return new ErodingObjectPool<>(pool, factor);
    452    }
    453
    454    /**
    455     * Returns a pool that adaptively decreases its size when idle objects are
    456     * no longer needed. This is intended as an always thread-safe alternative
    457     * to using an idle object evictor provided by many pool implementations.
    458     * This is also an effective way to shrink FIFO ordered pools that
    459     * experience load spikes.
    460     *
    461     * @param keyedPool
    462     *            the KeyedObjectPool to be decorated so it shrinks its idle
    463     *            count when possible.
    464     * @param <K> the type of the pool key
    465     * @param <V> the type of pool entries
    466     * @throws IllegalArgumentException
    467     *             when {@code keyedPool} is {@code null}.
    468     * @return a pool that adaptively decreases its size when idle objects are
    469     *         no longer needed.
    470     * @see #erodingPool(KeyedObjectPool, float)
    471     * @see #erodingPool(KeyedObjectPool, float, boolean)
    472     */
    473    public static <K, V> KeyedObjectPool<K, V> erodingPool(
    474            final KeyedObjectPool<K, V> keyedPool) {
    475        return erodingPool(keyedPool, 1f);
    476    }
    477
    478    /**
    479     * Returns a pool that adaptively decreases its size when idle objects are
    480     * no longer needed. This is intended as an always thread-safe alternative
    481     * to using an idle object evictor provided by many pool implementations.
    482     * This is also an effective way to shrink FIFO ordered pools that
    483     * experience load spikes.
    484     * <p>
    485     * The factor parameter provides a mechanism to tweak the rate at which the
    486     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
    487     * try to shrink its size more often. Values greater than 1 cause the pool
    488     * to less frequently try to shrink its size.
    489     * </p>
    490     *
    491     * @param keyedPool
    492     *            the KeyedObjectPool to be decorated so it shrinks its idle
    493     *            count when possible.
    494     * @param factor
    495     *            a positive value to scale the rate at which the pool tries to
    496     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
    497     *            shrinks more aggressively. If 1 &lt; factor then the pool
    498     *            shrinks less aggressively.
    499     * @param <K> the type of the pool key
    500     * @param <V> the type of pool entries
    501     * @throws IllegalArgumentException
    502     *             when {@code keyedPool} is {@code null} or when {@code factor}
    503     *             is not positive.
    504     * @return a pool that adaptively decreases its size when idle objects are
    505     *         no longer needed.
    506     * @see #erodingPool(KeyedObjectPool, float, boolean)
    507     */
    508    public static <K, V> KeyedObjectPool<K, V> erodingPool(
    509            final KeyedObjectPool<K, V> keyedPool, final float factor) {
    510        return erodingPool(keyedPool, factor, false);
    511    }
    512
    513    /**
    514     * Returns a pool that adaptively decreases its size when idle objects are
    515     * no longer needed. This is intended as an always thread-safe alternative
    516     * to using an idle object evictor provided by many pool implementations.
    517     * This is also an effective way to shrink FIFO ordered pools that
    518     * experience load spikes.
    519     * <p>
    520     * The factor parameter provides a mechanism to tweak the rate at which the
    521     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
    522     * try to shrink its size more often. Values greater than 1 cause the pool
    523     * to less frequently try to shrink its size.
    524     * </p>
    525     * <p>
    526     * The perKey parameter determines if the pool shrinks on a whole pool basis
    527     * or a per key basis. When perKey is false, the keys do not have an effect
    528     * on the rate at which the pool tries to shrink its size. When perKey is
    529     * true, each key is shrunk independently.
    530     * </p>
    531     *
    532     * @param keyedPool
    533     *            the KeyedObjectPool to be decorated so it shrinks its idle
    534     *            count when possible.
    535     * @param factor
    536     *            a positive value to scale the rate at which the pool tries to
    537     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
    538     *            shrinks more aggressively. If 1 &lt; factor then the pool
    539     *            shrinks less aggressively.
    540     * @param perKey
    541     *            when true, each key is treated independently.
    542     * @param <K> the type of the pool key
    543     * @param <V> the type of pool entries
    544     * @throws IllegalArgumentException
    545     *             when {@code keyedPool} is {@code null} or when {@code factor}
    546     *             is not positive.
    547     * @return a pool that adaptively decreases its size when idle objects are
    548     *         no longer needed.
    549     * @see #erodingPool(KeyedObjectPool)
    550     * @see #erodingPool(KeyedObjectPool, float)
    551     */
    552    public static <K, V> KeyedObjectPool<K, V> erodingPool(
    553            final KeyedObjectPool<K, V> keyedPool, final float factor,
    554            final boolean perKey) {
    555        if (keyedPool == null) {
    556            throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
    557        }
    558        if (factor <= 0f) {
    559            throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
    560        }
    561        if (perKey) {
    562            return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor);
    563        }
    564        return new ErodingKeyedObjectPool<>(keyedPool, factor);
    565    }
    566
    567    /**
    568     * Gets the {@code Timer} for checking keyedPool's idle count.
    569     *
    570     * @return the {@link Timer} for checking keyedPool's idle count.
    571     */
    572    private static Timer getMinIdleTimer() {
    573        return TimerHolder.MIN_IDLE_TIMER;
    574    }
    575
    576    /**
    577     * Timer task that adds objects to the pool until the number of idle
    578     * instances reaches the configured minIdle. Note that this is not the same
    579     * as the pool's minIdle setting.
    580     *
    581     * @param <T> type of objects in the pool
    582     */
    583    private static final class ObjectPoolMinIdleTimerTask<T> extends TimerTask {
    584
    585        /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
    586        private final int minIdle;
    587
    588        /** Object pool */
    589        private final ObjectPool<T> pool;
    590
    591        /**
    592         * Create a new ObjectPoolMinIdleTimerTask for the given pool with the
    593         * given minIdle setting.
    594         *
    595         * @param pool
    596         *            object pool
    597         * @param minIdle
    598         *            number of idle instances to maintain
    599         * @throws IllegalArgumentException
    600         *             if the pool is null
    601         */
    602        ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle)
    603                throws IllegalArgumentException {
    604            if (pool == null) {
    605                throw new IllegalArgumentException(MSG_NULL_POOL);
    606            }
    607            this.pool = pool;
    608            this.minIdle = minIdle;
    609        }
    610
    611        /**
    612         * {@inheritDoc}
    613         */
    614        @Override
    615        public void run() {
    616            boolean success = false;
    617            try {
    618                if (pool.getNumIdle() < minIdle) {
    619                    pool.addObject();
    620                }
    621                success = true;
    622
    623            } catch (final Exception e) {
    624                cancel();
    625            } finally {
    626                // detect other types of Throwable and cancel this Timer
    627                if (!success) {
    628                    cancel();
    629                }
    630            }
    631        }
    632
    633        /**
    634         * {@inheritDoc}
    635         */
    636        @Override
    637        public String toString() {
    638            final StringBuilder sb = new StringBuilder();
    639            sb.append("ObjectPoolMinIdleTimerTask");
    640            sb.append("{minIdle=").append(minIdle);
    641            sb.append(", pool=").append(pool);
    642            sb.append('}');
    643            return sb.toString();
    644        }
    645    }
    646
    647    /**
    648     * Timer task that adds objects to the pool until the number of idle
    649     * instances for the given key reaches the configured minIdle. Note that
    650     * this is not the same as the pool's minIdle setting.
    651     *
    652     * @param <K> object pool key type
    653     * @param <V> object pool value type
    654     */
    655    private static final class KeyedObjectPoolMinIdleTimerTask<K, V> extends
    656            TimerTask {
    657
    658        /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */
    659        private final int minIdle;
    660
    661        /** Key to ensure minIdle for */
    662        private final K key;
    663
    664        /** Keyed object pool */
    665        private final KeyedObjectPool<K, V> keyedPool;
    666
    667        /**
    668         * Creates a new KeyedObjecPoolMinIdleTimerTask.
    669         *
    670         * @param keyedPool
    671         *            keyed object pool
    672         * @param key
    673         *            key to ensure minimum number of idle instances
    674         * @param minIdle
    675         *            minimum number of idle instances
    676         * @throws IllegalArgumentException
    677         *             if the key is null
    678         */
    679        KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool<K, V> keyedPool,
    680                final K key, final int minIdle) throws IllegalArgumentException {
    681            if (keyedPool == null) {
    682                throw new IllegalArgumentException(
    683                        MSG_NULL_KEYED_POOL);
    684            }
    685            this.keyedPool = keyedPool;
    686            this.key = key;
    687            this.minIdle = minIdle;
    688        }
    689
    690        /**
    691         * {@inheritDoc}
    692         */
    693        @Override
    694        public void run() {
    695            boolean success = false;
    696            try {
    697                if (keyedPool.getNumIdle(key) < minIdle) {
    698                    keyedPool.addObject(key);
    699                }
    700                success = true;
    701
    702            } catch (final Exception e) {
    703                cancel();
    704
    705            } finally {
    706                // detect other types of Throwable and cancel this Timer
    707                if (!success) {
    708                    cancel();
    709                }
    710            }
    711        }
    712
    713        /**
    714         * {@inheritDoc}
    715         */
    716        @Override
    717        public String toString() {
    718            final StringBuilder sb = new StringBuilder();
    719            sb.append("KeyedObjectPoolMinIdleTimerTask");
    720            sb.append("{minIdle=").append(minIdle);
    721            sb.append(", key=").append(key);
    722            sb.append(", keyedPool=").append(keyedPool);
    723            sb.append('}');
    724            return sb.toString();
    725        }
    726    }
    727
    728    /**
    729     * A synchronized (thread-safe) ObjectPool backed by the specified
    730     * ObjectPool.
    731     * <p>
    732     * <b>Note:</b> This should not be used on pool implementations that already
    733     * provide proper synchronization such as the pools provided in the Commons
    734     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
    735     * objects to be returned before allowing another one to be borrowed with
    736     * another layer of synchronization will cause liveliness issues or a
    737     * deadlock.
    738     * </p>
    739     *
    740     * @param <T> type of objects in the pool
    741     */
    742    private static final class SynchronizedObjectPool<T> implements ObjectPool<T> {
    743
    744        /**
    745         * Object whose monitor is used to synchronize methods on the wrapped
    746         * pool.
    747         */
    748        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    749
    750        /** the underlying object pool */
    751        private final ObjectPool<T> pool;
    752
    753        /**
    754         * Creates a new SynchronizedObjectPool wrapping the given pool.
    755         *
    756         * @param pool
    757         *            the ObjectPool to be "wrapped" in a synchronized
    758         *            ObjectPool.
    759         * @throws IllegalArgumentException
    760         *             if the pool is null
    761         */
    762        SynchronizedObjectPool(final ObjectPool<T> pool)
    763                throws IllegalArgumentException {
    764            if (pool == null) {
    765                throw new IllegalArgumentException(MSG_NULL_POOL);
    766            }
    767            this.pool = pool;
    768        }
    769
    770        /**
    771         * {@inheritDoc}
    772         */
    773        @Override
    774        public T borrowObject() throws Exception, NoSuchElementException,
    775                IllegalStateException {
    776            final WriteLock writeLock = readWriteLock.writeLock();
    777            writeLock.lock();
    778            try {
    779                return pool.borrowObject();
    780            } finally {
    781                writeLock.unlock();
    782            }
    783        }
    784
    785        /**
    786         * {@inheritDoc}
    787         */
    788        @Override
    789        public void returnObject(final T obj) {
    790            final WriteLock writeLock = readWriteLock.writeLock();
    791            writeLock.lock();
    792            try {
    793                pool.returnObject(obj);
    794            } catch (final Exception e) {
    795                // swallowed as of Pool 2
    796            } finally {
    797                writeLock.unlock();
    798            }
    799        }
    800
    801        /**
    802         * {@inheritDoc}
    803         */
    804        @Override
    805        public void invalidateObject(final T obj) {
    806            final WriteLock writeLock = readWriteLock.writeLock();
    807            writeLock.lock();
    808            try {
    809                pool.invalidateObject(obj);
    810            } catch (final Exception e) {
    811                // swallowed as of Pool 2
    812            } finally {
    813                writeLock.unlock();
    814            }
    815        }
    816
    817        /**
    818         * {@inheritDoc}
    819         */
    820        @Override
    821        public void addObject() throws Exception, IllegalStateException,
    822                UnsupportedOperationException {
    823            final WriteLock writeLock = readWriteLock.writeLock();
    824            writeLock.lock();
    825            try {
    826                pool.addObject();
    827            } finally {
    828                writeLock.unlock();
    829            }
    830        }
    831
    832        /**
    833         * {@inheritDoc}
    834         */
    835        @Override
    836        public int getNumIdle() {
    837            final ReadLock readLock = readWriteLock.readLock();
    838            readLock.lock();
    839            try {
    840                return pool.getNumIdle();
    841            } finally {
    842                readLock.unlock();
    843            }
    844        }
    845
    846        /**
    847         * {@inheritDoc}
    848         */
    849        @Override
    850        public int getNumActive() {
    851            final ReadLock readLock = readWriteLock.readLock();
    852            readLock.lock();
    853            try {
    854                return pool.getNumActive();
    855            } finally {
    856                readLock.unlock();
    857            }
    858        }
    859
    860        /**
    861         * {@inheritDoc}
    862         */
    863        @Override
    864        public void clear() throws Exception, UnsupportedOperationException {
    865            final WriteLock writeLock = readWriteLock.writeLock();
    866            writeLock.lock();
    867            try {
    868                pool.clear();
    869            } finally {
    870                writeLock.unlock();
    871            }
    872        }
    873
    874        /**
    875         * {@inheritDoc}
    876         */
    877        @Override
    878        public void close() {
    879            final WriteLock writeLock = readWriteLock.writeLock();
    880            writeLock.lock();
    881            try {
    882                pool.close();
    883            } catch (final Exception e) {
    884                // swallowed as of Pool 2
    885            } finally {
    886                writeLock.unlock();
    887            }
    888        }
    889
    890        /**
    891         * {@inheritDoc}
    892         */
    893        @Override
    894        public String toString() {
    895            final StringBuilder sb = new StringBuilder();
    896            sb.append("SynchronizedObjectPool");
    897            sb.append("{pool=").append(pool);
    898            sb.append('}');
    899            return sb.toString();
    900        }
    901    }
    902
    903    /**
    904     * A synchronized (thread-safe) KeyedObjectPool backed by the specified
    905     * KeyedObjectPool.
    906     * <p>
    907     * <b>Note:</b> This should not be used on pool implementations that already
    908     * provide proper synchronization such as the pools provided in the Commons
    909     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
    910     * objects to be returned before allowing another one to be borrowed with
    911     * another layer of synchronization will cause liveliness issues or a
    912     * deadlock.
    913     * </p>
    914     *
    915     * @param <K> object pool key type
    916     * @param <V> object pool value type
    917     */
    918    private static final class SynchronizedKeyedObjectPool<K, V> implements
    919            KeyedObjectPool<K, V> {
    920
    921        /**
    922         * Object whose monitor is used to synchronize methods on the wrapped
    923         * pool.
    924         */
    925        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    926
    927        /** Underlying object pool */
    928        private final KeyedObjectPool<K, V> keyedPool;
    929
    930        /**
    931         * Creates a new SynchronizedKeyedObjectPool wrapping the given pool
    932         *
    933         * @param keyedPool
    934         *            KeyedObjectPool to wrap
    935         * @throws IllegalArgumentException
    936         *             if keyedPool is null
    937         */
    938        SynchronizedKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool)
    939                throws IllegalArgumentException {
    940            if (keyedPool == null) {
    941                throw new IllegalArgumentException(
    942                        MSG_NULL_KEYED_POOL);
    943            }
    944            this.keyedPool = keyedPool;
    945        }
    946
    947        /**
    948         * {@inheritDoc}
    949         */
    950        @Override
    951        public V borrowObject(final K key) throws Exception,
    952                NoSuchElementException, IllegalStateException {
    953            final WriteLock writeLock = readWriteLock.writeLock();
    954            writeLock.lock();
    955            try {
    956                return keyedPool.borrowObject(key);
    957            } finally {
    958                writeLock.unlock();
    959            }
    960        }
    961
    962        /**
    963         * {@inheritDoc}
    964         */
    965        @Override
    966        public void returnObject(final K key, final V obj) {
    967            final WriteLock writeLock = readWriteLock.writeLock();
    968            writeLock.lock();
    969            try {
    970                keyedPool.returnObject(key, obj);
    971            } catch (final Exception e) {
    972                // swallowed
    973            } finally {
    974                writeLock.unlock();
    975            }
    976        }
    977
    978        /**
    979         * {@inheritDoc}
    980         */
    981        @Override
    982        public void invalidateObject(final K key, final V obj) {
    983            final WriteLock writeLock = readWriteLock.writeLock();
    984            writeLock.lock();
    985            try {
    986                keyedPool.invalidateObject(key, obj);
    987            } catch (final Exception e) {
    988                // swallowed as of Pool 2
    989            } finally {
    990                writeLock.unlock();
    991            }
    992        }
    993
    994        /**
    995         * {@inheritDoc}
    996         */
    997        @Override
    998        public void addObject(final K key) throws Exception,
    999                IllegalStateException, UnsupportedOperationException {
    1000            final WriteLock writeLock = readWriteLock.writeLock();
    1001            writeLock.lock();
    1002            try {
    1003                keyedPool.addObject(key);
    1004            } finally {
    1005                writeLock.unlock();
    1006            }
    1007        }
    1008
    1009        /**
    1010         * {@inheritDoc}
    1011         */
    1012        @Override
    1013        public int getNumIdle(final K key) {
    1014            final ReadLock readLock = readWriteLock.readLock();
    1015            readLock.lock();
    1016            try {
    1017                return keyedPool.getNumIdle(key);
    1018            } finally {
    1019                readLock.unlock();
    1020            }
    1021        }
    1022
    1023        /**
    1024         * {@inheritDoc}
    1025         */
    1026        @Override
    1027        public int getNumActive(final K key) {
    1028            final ReadLock readLock = readWriteLock.readLock();
    1029            readLock.lock();
    1030            try {
    1031                return keyedPool.getNumActive(key);
    1032            } finally {
    1033                readLock.unlock();
    1034            }
    1035        }
    1036
    1037        /**
    1038         * {@inheritDoc}
    1039         */
    1040        @Override
    1041        public int getNumIdle() {
    1042            final ReadLock readLock = readWriteLock.readLock();
    1043            readLock.lock();
    1044            try {
    1045                return keyedPool.getNumIdle();
    1046            } finally {
    1047                readLock.unlock();
    1048            }
    1049        }
    1050
    1051        /**
    1052         * {@inheritDoc}
    1053         */
    1054        @Override
    1055        public int getNumActive() {
    1056            final ReadLock readLock = readWriteLock.readLock();
    1057            readLock.lock();
    1058            try {
    1059                return keyedPool.getNumActive();
    1060            } finally {
    1061                readLock.unlock();
    1062            }
    1063        }
    1064
    1065        /**
    1066         * {@inheritDoc}
    1067         */
    1068        @Override
    1069        public void clear() throws Exception, UnsupportedOperationException {
    1070            final WriteLock writeLock = readWriteLock.writeLock();
    1071            writeLock.lock();
    1072            try {
    1073                keyedPool.clear();
    1074            } finally {
    1075                writeLock.unlock();
    1076            }
    1077        }
    1078
    1079        /**
    1080         * {@inheritDoc}
    1081         */
    1082        @Override
    1083        public void clear(final K key) throws Exception,
    1084                UnsupportedOperationException {
    1085            final WriteLock writeLock = readWriteLock.writeLock();
    1086            writeLock.lock();
    1087            try {
    1088                keyedPool.clear(key);
    1089            } finally {
    1090                writeLock.unlock();
    1091            }
    1092        }
    1093
    1094        /**
    1095         * {@inheritDoc}
    1096         */
    1097        @Override
    1098        public void close() {
    1099            final WriteLock writeLock = readWriteLock.writeLock();
    1100            writeLock.lock();
    1101            try {
    1102                keyedPool.close();
    1103            } catch (final Exception e) {
    1104                // swallowed as of Pool 2
    1105            } finally {
    1106                writeLock.unlock();
    1107            }
    1108        }
    1109
    1110        /**
    1111         * {@inheritDoc}
    1112         */
    1113        @Override
    1114        public String toString() {
    1115            final StringBuilder sb = new StringBuilder();
    1116            sb.append("SynchronizedKeyedObjectPool");
    1117            sb.append("{keyedPool=").append(keyedPool);
    1118            sb.append('}');
    1119            return sb.toString();
    1120        }
    1121    }
    1122
    1123    /**
    1124     * A fully synchronized PooledObjectFactory that wraps a
    1125     * PooledObjectFactory and synchronizes access to the wrapped factory
    1126     * methods.
    1127     * <p>
    1128     * <b>Note:</b> This should not be used on pool implementations that already
    1129     * provide proper synchronization such as the pools provided in the Commons
    1130     * Pool library.
    1131     * </p>
    1132     *
    1133     * @param <T> pooled object factory type
    1134     */
    1135    private static final class SynchronizedPooledObjectFactory<T> implements
    1136            PooledObjectFactory<T> {
    1137
    1138        /** Synchronization lock */
    1139        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
    1140
    1141        /** Wrapped factory */
    1142        private final PooledObjectFactory<T> factory;
    1143
    1144        /**
    1145         * Creates a SynchronizedPoolableObjectFactory wrapping the given
    1146         * factory.
    1147         *
    1148         * @param factory
    1149         *            underlying factory to wrap
    1150         * @throws IllegalArgumentException
    1151         *             if the factory is null
    1152         */
    1153        SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
    1154                throws IllegalArgumentException {
    1155            if (factory == null) {
    1156                throw new IllegalArgumentException("factory must not be null.");
    1157            }
    1158            this.factory = factory;
    1159        }
    1160
    1161        /**
    1162         * {@inheritDoc}
    1163         */
    1164        @Override
    1165        public PooledObject<T> makeObject() throws Exception {
    1166            writeLock.lock();
    1167            try {
    1168                return factory.makeObject();
    1169            } finally {
    1170                writeLock.unlock();
    1171            }
    1172        }
    1173
    1174        /**
    1175         * {@inheritDoc}
    1176         */
    1177        @Override
    1178        public void destroyObject(final PooledObject<T> p) throws Exception {
    1179            writeLock.lock();
    1180            try {
    1181                factory.destroyObject(p);
    1182            } finally {
    1183                writeLock.unlock();
    1184            }
    1185        }
    1186
    1187        /**
    1188         * {@inheritDoc}
    1189         */
    1190        @Override
    1191        public boolean validateObject(final PooledObject<T> p) {
    1192            writeLock.lock();
    1193            try {
    1194                return factory.validateObject(p);
    1195            } finally {
    1196                writeLock.unlock();
    1197            }
    1198        }
    1199
    1200        /**
    1201         * {@inheritDoc}
    1202         */
    1203        @Override
    1204        public void activateObject(final PooledObject<T> p) throws Exception {
    1205            writeLock.lock();
    1206            try {
    1207                factory.activateObject(p);
    1208            } finally {
    1209                writeLock.unlock();
    1210            }
    1211        }
    1212
    1213        /**
    1214         * {@inheritDoc}
    1215         */
    1216        @Override
    1217        public void passivateObject(final PooledObject<T> p) throws Exception {
    1218            writeLock.lock();
    1219            try {
    1220                factory.passivateObject(p);
    1221            } finally {
    1222                writeLock.unlock();
    1223            }
    1224        }
    1225
    1226        /**
    1227         * {@inheritDoc}
    1228         */
    1229        @Override
    1230        public String toString() {
    1231            final StringBuilder sb = new StringBuilder();
    1232            sb.append("SynchronizedPoolableObjectFactory");
    1233            sb.append("{factory=").append(factory);
    1234            sb.append('}');
    1235            return sb.toString();
    1236        }
    1237    }
    1238
    1239    /**
    1240     * A fully synchronized KeyedPooledObjectFactory that wraps a
    1241     * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
    1242     * methods.
    1243     * <p>
    1244     * <b>Note:</b> This should not be used on pool implementations that already
    1245     * provide proper synchronization such as the pools provided in the Commons
    1246     * Pool library.
    1247     * </p>
    1248     *
    1249     * @param <K> pooled object factory key type
    1250     * @param <V> pooled object factory key value
    1251     */
    1252    private static final class SynchronizedKeyedPooledObjectFactory<K, V>
    1253            implements KeyedPooledObjectFactory<K, V> {
    1254
    1255        /** Synchronization lock */
    1256        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
    1257
    1258        /** Wrapped factory */
    1259        private final KeyedPooledObjectFactory<K, V> keyedFactory;
    1260
    1261        /**
    1262         * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
    1263         * factory.
    1264         *
    1265         * @param keyedFactory
    1266         *            underlying factory to wrap
    1267         * @throws IllegalArgumentException
    1268         *             if the factory is null
    1269         */
    1270        SynchronizedKeyedPooledObjectFactory(
    1271                final KeyedPooledObjectFactory<K, V> keyedFactory)
    1272                throws IllegalArgumentException {
    1273            if (keyedFactory == null) {
    1274                throw new IllegalArgumentException(
    1275                        "keyedFactory must not be null.");
    1276            }
    1277            this.keyedFactory = keyedFactory;
    1278        }
    1279
    1280        /**
    1281         * {@inheritDoc}
    1282         */
    1283        @Override
    1284        public PooledObject<V> makeObject(final K key) throws Exception {
    1285            writeLock.lock();
    1286            try {
    1287                return keyedFactory.makeObject(key);
    1288            } finally {
    1289                writeLock.unlock();
    1290            }
    1291        }
    1292
    1293        /**
    1294         * {@inheritDoc}
    1295         */
    1296        @Override
    1297        public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
    1298            writeLock.lock();
    1299            try {
    1300                keyedFactory.destroyObject(key, p);
    1301            } finally {
    1302                writeLock.unlock();
    1303            }
    1304        }
    1305
    1306        /**
    1307         * {@inheritDoc}
    1308         */
    1309        @Override
    1310        public boolean validateObject(final K key, final PooledObject<V> p) {
    1311            writeLock.lock();
    1312            try {
    1313                return keyedFactory.validateObject(key, p);
    1314            } finally {
    1315                writeLock.unlock();
    1316            }
    1317        }
    1318
    1319        /**
    1320         * {@inheritDoc}
    1321         */
    1322        @Override
    1323        public void activateObject(final K key, final PooledObject<V> p) throws Exception {
    1324            writeLock.lock();
    1325            try {
    1326                keyedFactory.activateObject(key, p);
    1327            } finally {
    1328                writeLock.unlock();
    1329            }
    1330        }
    1331
    1332        /**
    1333         * {@inheritDoc}
    1334         */
    1335        @Override
    1336        public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
    1337            writeLock.lock();
    1338            try {
    1339                keyedFactory.passivateObject(key, p);
    1340            } finally {
    1341                writeLock.unlock();
    1342            }
    1343        }
    1344
    1345        /**
    1346         * {@inheritDoc}
    1347         */
    1348        @Override
    1349        public String toString() {
    1350            final StringBuilder sb = new StringBuilder();
    1351            sb.append("SynchronizedKeyedPoolableObjectFactory");
    1352            sb.append("{keyedFactory=").append(keyedFactory);
    1353            sb.append('}');
    1354            return sb.toString();
    1355        }
    1356    }
    1357
    1358    /**
    1359     * Encapsulate the logic for when the next poolable object should be
    1360     * discarded. Each time update is called, the next time to shrink is
    1361     * recomputed, based on the float factor, number of idle instances in the
    1362     * pool and high water mark. Float factor is assumed to be between 0 and 1.
    1363     * Values closer to 1 cause less frequent erosion events. Erosion event
    1364     * timing also depends on numIdle. When this value is relatively high (close
    1365     * to previously established high water mark), erosion occurs more
    1366     * frequently.
    1367     */
    1368    private static final class ErodingFactor {
    1369        /** Determines frequency of "erosion" events */
    1370        private final float factor;
    1371
    1372        /** Time of next shrink event */
    1373        private transient volatile long nextShrink;
    1374
    1375        /** High water mark - largest numIdle encountered */
    1376        private transient volatile int idleHighWaterMark;
    1377
    1378        /**
    1379         * Creates a new ErodingFactor with the given erosion factor.
    1380         *
    1381         * @param factor
    1382         *            erosion factor
    1383         */
    1384        public ErodingFactor(final float factor) {
    1385            this.factor = factor;
    1386            nextShrink = System.currentTimeMillis() + (long) (900000 * factor); // now
    1387                                                                                // +
    1388                                                                                // 15
    1389                                                                                // min
    1390                                                                                // *
    1391                                                                                // factor
    1392            idleHighWaterMark = 1;
    1393        }
    1394
    1395        /**
    1396         * Updates internal state using the supplied time and numIdle.
    1397         *
    1398         * @param now
    1399         *            current time
    1400         * @param numIdle
    1401         *            number of idle elements in the pool
    1402         */
    1403        public void update(final long now, final int numIdle) {
    1404            final int idle = Math.max(0, numIdle);
    1405            idleHighWaterMark = Math.max(idle, idleHighWaterMark);
    1406            final float maxInterval = 15f;
    1407            final float minutes = maxInterval +
    1408                    ((1f - maxInterval) / idleHighWaterMark) * idle;
    1409            nextShrink = now + (long) (minutes * 60000f * factor);
    1410        }
    1411
    1412        /**
    1413         * Returns the time of the next erosion event.
    1414         *
    1415         * @return next shrink time
    1416         */
    1417        public long getNextShrink() {
    1418            return nextShrink;
    1419        }
    1420
    1421        /**
    1422         * {@inheritDoc}
    1423         */
    1424        @Override
    1425        public String toString() {
    1426            return "ErodingFactor{" + "factor=" + factor +
    1427                    ", idleHighWaterMark=" + idleHighWaterMark + '}';
    1428        }
    1429    }
    1430
    1431    /**
    1432     * Decorates an object pool, adding "eroding" behavior. Based on the
    1433     * configured {@link #factor erosion factor}, objects returning to the pool
    1434     * may be invalidated instead of being added to idle capacity.
    1435     *
    1436     * @param <T> type of objects in the pool
    1437     */
    1438    private static class ErodingObjectPool<T> implements ObjectPool<T> {
    1439
    1440        /** Underlying object pool */
    1441        private final ObjectPool<T> pool;
    1442
    1443        /** Erosion factor */
    1444        private final ErodingFactor factor;
    1445
    1446        /**
    1447         * Creates an ErodingObjectPool wrapping the given pool using the
    1448         * specified erosion factor.
    1449         *
    1450         * @param pool
    1451         *            underlying pool
    1452         * @param factor
    1453         *            erosion factor - determines the frequency of erosion
    1454         *            events
    1455         * @see #factor
    1456         */
    1457        public ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
    1458            this.pool = pool;
    1459            this.factor = new ErodingFactor(factor);
    1460        }
    1461
    1462        /**
    1463         * {@inheritDoc}
    1464         */
    1465        @Override
    1466        public T borrowObject() throws Exception, NoSuchElementException,
    1467                IllegalStateException {
    1468            return pool.borrowObject();
    1469        }
    1470
    1471        /**
    1472         * Returns obj to the pool, unless erosion is triggered, in which case
    1473         * obj is invalidated. Erosion is triggered when there are idle
    1474         * instances in the pool and more than the {@link #factor erosion
    1475         * factor}-determined time has elapsed since the last returnObject
    1476         * activation.
    1477         *
    1478         * @param obj
    1479         *            object to return or invalidate
    1480         * @see #factor
    1481         */
    1482        @Override
    1483        public void returnObject(final T obj) {
    1484            boolean discard = false;
    1485            final long now = System.currentTimeMillis();
    1486            synchronized (pool) {
    1487                if (factor.getNextShrink() < now) { // XXX: Pool 3: move test
    1488                                                    // out of sync block
    1489                    final int numIdle = pool.getNumIdle();
    1490                    if (numIdle > 0) {
    1491                        discard = true;
    1492                    }
    1493
    1494                    factor.update(now, numIdle);
    1495                }
    1496            }
    1497            try {
    1498                if (discard) {
    1499                    pool.invalidateObject(obj);
    1500                } else {
    1501                    pool.returnObject(obj);
    1502                }
    1503            } catch (final Exception e) {
    1504                // swallowed
    1505            }
    1506        }
    1507
    1508        /**
    1509         * {@inheritDoc}
    1510         */
    1511        @Override
    1512        public void invalidateObject(final T obj) {
    1513            try {
    1514                pool.invalidateObject(obj);
    1515            } catch (final Exception e) {
    1516                // swallowed
    1517            }
    1518        }
    1519
    1520        /**
    1521         * {@inheritDoc}
    1522         */
    1523        @Override
    1524        public void addObject() throws Exception, IllegalStateException,
    1525                UnsupportedOperationException {
    1526            pool.addObject();
    1527        }
    1528
    1529        /**
    1530         * {@inheritDoc}
    1531         */
    1532        @Override
    1533        public int getNumIdle() {
    1534            return pool.getNumIdle();
    1535        }
    1536
    1537        /**
    1538         * {@inheritDoc}
    1539         */
    1540        @Override
    1541        public int getNumActive() {
    1542            return pool.getNumActive();
    1543        }
    1544
    1545        /**
    1546         * {@inheritDoc}
    1547         */
    1548        @Override
    1549        public void clear() throws Exception, UnsupportedOperationException {
    1550            pool.clear();
    1551        }
    1552
    1553        /**
    1554         * {@inheritDoc}
    1555         */
    1556        @Override
    1557        public void close() {
    1558            try {
    1559                pool.close();
    1560            } catch (final Exception e) {
    1561                // swallowed
    1562            }
    1563        }
    1564
    1565        /**
    1566         * {@inheritDoc}
    1567         */
    1568        @Override
    1569        public String toString() {
    1570            return "ErodingObjectPool{" + "factor=" + factor + ", pool=" +
    1571                    pool + '}';
    1572        }
    1573    }
    1574
    1575    /**
    1576     * Decorates a keyed object pool, adding "eroding" behavior. Based on the
    1577     * configured erosion factor, objects returning to the pool
    1578     * may be invalidated instead of being added to idle capacity.
    1579     *
    1580     * @param <K> object pool key type
    1581     * @param <V> object pool value type
    1582     */
    1583    private static class ErodingKeyedObjectPool<K, V> implements
    1584            KeyedObjectPool<K, V> {
    1585
    1586        /** Underlying pool */
    1587        private final KeyedObjectPool<K, V> keyedPool;
    1588
    1589        /** Erosion factor */
    1590        private final ErodingFactor erodingFactor;
    1591
    1592        /**
    1593         * Creates an ErodingObjectPool wrapping the given pool using the
    1594         * specified erosion factor.
    1595         *
    1596         * @param keyedPool
    1597         *            underlying pool
    1598         * @param factor
    1599         *            erosion factor - determines the frequency of erosion
    1600         *            events
    1601         * @see #erodingFactor
    1602         */
    1603        public ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
    1604                final float factor) {
    1605            this(keyedPool, new ErodingFactor(factor));
    1606        }
    1607
    1608        /**
    1609         * Creates an ErodingObjectPool wrapping the given pool using the
    1610         * specified erosion factor.
    1611         *
    1612         * @param keyedPool
    1613         *            underlying pool - must not be null
    1614         * @param erodingFactor
    1615         *            erosion factor - determines the frequency of erosion
    1616         *            events
    1617         * @see #erodingFactor
    1618         */
    1619        protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
    1620                final ErodingFactor erodingFactor) {
    1621            if (keyedPool == null) {
    1622                throw new IllegalArgumentException(
    1623                        MSG_NULL_KEYED_POOL);
    1624            }
    1625            this.keyedPool = keyedPool;
    1626            this.erodingFactor = erodingFactor;
    1627        }
    1628
    1629        /**
    1630         * {@inheritDoc}
    1631         */
    1632        @Override
    1633        public V borrowObject(final K key) throws Exception,
    1634                NoSuchElementException, IllegalStateException {
    1635            return keyedPool.borrowObject(key);
    1636        }
    1637
    1638        /**
    1639         * Returns obj to the pool, unless erosion is triggered, in which case
    1640         * obj is invalidated. Erosion is triggered when there are idle
    1641         * instances in the pool associated with the given key and more than the
    1642         * configured {@link #erodingFactor erosion factor} time has elapsed
    1643         * since the last returnObject activation.
    1644         *
    1645         * @param obj
    1646         *            object to return or invalidate
    1647         * @param key
    1648         *            key
    1649         * @see #erodingFactor
    1650         */
    1651        @Override
    1652        public void returnObject(final K key, final V obj) throws Exception {
    1653            boolean discard = false;
    1654            final long now = System.currentTimeMillis();
    1655            final ErodingFactor factor = getErodingFactor(key);
    1656            synchronized (keyedPool) {
    1657                if (factor.getNextShrink() < now) {
    1658                    final int numIdle = getNumIdle(key);
    1659                    if (numIdle > 0) {
    1660                        discard = true;
    1661                    }
    1662
    1663                    factor.update(now, numIdle);
    1664                }
    1665            }
    1666            try {
    1667                if (discard) {
    1668                    keyedPool.invalidateObject(key, obj);
    1669                } else {
    1670                    keyedPool.returnObject(key, obj);
    1671                }
    1672            } catch (final Exception e) {
    1673                // swallowed
    1674            }
    1675        }
    1676
    1677        /**
    1678         * Returns the eroding factor for the given key
    1679         *
    1680         * @param key
    1681         *            key
    1682         * @return eroding factor for the given keyed pool
    1683         */
    1684        protected ErodingFactor getErodingFactor(final K key) {
    1685            return erodingFactor;
    1686        }
    1687
    1688        /**
    1689         * {@inheritDoc}
    1690         */
    1691        @Override
    1692        public void invalidateObject(final K key, final V obj) {
    1693            try {
    1694                keyedPool.invalidateObject(key, obj);
    1695            } catch (final Exception e) {
    1696                // swallowed
    1697            }
    1698        }
    1699
    1700        /**
    1701         * {@inheritDoc}
    1702         */
    1703        @Override
    1704        public void addObject(final K key) throws Exception,
    1705                IllegalStateException, UnsupportedOperationException {
    1706            keyedPool.addObject(key);
    1707        }
    1708
    1709        /**
    1710         * {@inheritDoc}
    1711         */
    1712        @Override
    1713        public int getNumIdle() {
    1714            return keyedPool.getNumIdle();
    1715        }
    1716
    1717        /**
    1718         * {@inheritDoc}
    1719         */
    1720        @Override
    1721        public int getNumIdle(final K key) {
    1722            return keyedPool.getNumIdle(key);
    1723        }
    1724
    1725        /**
    1726         * {@inheritDoc}
    1727         */
    1728        @Override
    1729        public int getNumActive() {
    1730            return keyedPool.getNumActive();
    1731        }
    1732
    1733        /**
    1734         * {@inheritDoc}
    1735         */
    1736        @Override
    1737        public int getNumActive(final K key) {
    1738            return keyedPool.getNumActive(key);
    1739        }
    1740
    1741        /**
    1742         * {@inheritDoc}
    1743         */
    1744        @Override
    1745        public void clear() throws Exception, UnsupportedOperationException {
    1746            keyedPool.clear();
    1747        }
    1748
    1749        /**
    1750         * {@inheritDoc}
    1751         */
    1752        @Override
    1753        public void clear(final K key) throws Exception,
    1754                UnsupportedOperationException {
    1755            keyedPool.clear(key);
    1756        }
    1757
    1758        /**
    1759         * {@inheritDoc}
    1760         */
    1761        @Override
    1762        public void close() {
    1763            try {
    1764                keyedPool.close();
    1765            } catch (final Exception e) {
    1766                // swallowed
    1767            }
    1768        }
    1769
    1770        /**
    1771         * Returns the underlying pool
    1772         *
    1773         * @return the keyed pool that this ErodingKeyedObjectPool wraps
    1774         */
    1775        protected KeyedObjectPool<K, V> getKeyedPool() {
    1776            return keyedPool;
    1777        }
    1778
    1779        /**
    1780         * {@inheritDoc}
    1781         */
    1782        @Override
    1783        public String toString() {
    1784            return "ErodingKeyedObjectPool{" + "factor=" +
    1785                    erodingFactor + ", keyedPool=" + keyedPool + '}';
    1786        }
    1787    }
    1788
    1789    /**
    1790     * Extends ErodingKeyedObjectPool to allow erosion to take place on a
    1791     * per-key basis. Timing of erosion events is tracked separately for
    1792     * separate keyed pools.
    1793     *
    1794     * @param <K> object pool key type
    1795     * @param <V> object pool value type
    1796     */
    1797    private static final class ErodingPerKeyKeyedObjectPool<K, V> extends
    1798            ErodingKeyedObjectPool<K, V> {
    1799
    1800        /** Erosion factor - same for all pools */
    1801        private final float factor;
    1802
    1803        /** Map of ErodingFactor instances keyed on pool keys */
    1804        private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<K, ErodingFactor>());
    1805
    1806        /**
    1807         * Creates a new ErordingPerKeyKeyedObjectPool decorating the given keyed
    1808         * pool with the specified erosion factor.
    1809         *
    1810         * @param keyedPool
    1811         *            underlying keyed pool
    1812         * @param factor
    1813         *            erosion factor
    1814         */
    1815        public ErodingPerKeyKeyedObjectPool(
    1816                final KeyedObjectPool<K, V> keyedPool, final float factor) {
    1817            super(keyedPool, null);
    1818            this.factor = factor;
    1819        }
    1820
    1821        /**
    1822         * {@inheritDoc}
    1823         */
    1824        @Override
    1825        protected ErodingFactor getErodingFactor(final K key) {
    1826            ErodingFactor eFactor = factors.get(key);
    1827            // this may result in two ErodingFactors being created for a key
    1828            // since they are small and cheap this is okay.
    1829            if (eFactor == null) {
    1830                eFactor = new ErodingFactor(this.factor);
    1831                factors.put(key, eFactor);
    1832            }
    1833            return eFactor;
    1834        }
    1835
    1836        /**
    1837         * {@inheritDoc}
    1838         */
    1839        @SuppressWarnings("resource") // getKeyedPool(): ivar access
    1840        @Override
    1841        public String toString() {
    1842            return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +
    1843                    ", keyedPool=" + getKeyedPool() + '}';
    1844        }
    1845    }
    1846}