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