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