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