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