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