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