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