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