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