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