001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.pool2; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Timer; 025import java.util.TimerTask; 026import java.util.concurrent.locks.ReentrantReadWriteLock; 027import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; 028import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; 029 030/** 031 * This class consists exclusively of static methods that operate on or return 032 * ObjectPool or KeyedObjectPool related interfaces. 033 * 034 * @since 2.0 035 */ 036public final class PoolUtils { 037 038 /** 039 * Encapsulate the logic for when the next poolable object should be 040 * discarded. Each time update is called, the next time to shrink is 041 * recomputed, based on the float factor, number of idle instances in the 042 * pool and high water mark. Float factor is assumed to be between 0 and 1. 043 * Values closer to 1 cause less frequent erosion events. Erosion event 044 * timing also depends on numIdle. When this value is relatively high (close 045 * to previously established high water mark), erosion occurs more 046 * frequently. 047 */ 048 private static final class ErodingFactor { 049 /** Determines frequency of "erosion" events */ 050 private final float factor; 051 052 /** Time of next shrink event */ 053 private transient volatile long nextShrinkMillis; 054 055 /** High water mark - largest numIdle encountered */ 056 private transient volatile int idleHighWaterMark; 057 058 /** 059 * Creates a new ErodingFactor with the given erosion factor. 060 * 061 * @param factor 062 * erosion factor 063 */ 064 public ErodingFactor(final float factor) { 065 this.factor = factor; 066 nextShrinkMillis = System.currentTimeMillis() + (long) (900000 * factor); // now + 15 min * factor 067 idleHighWaterMark = 1; 068 } 069 070 /** 071 * Gets the time of the next erosion event. 072 * 073 * @return next shrink time 074 */ 075 public long getNextShrink() { 076 return nextShrinkMillis; 077 } 078 079 /** 080 * {@inheritDoc} 081 */ 082 @Override 083 public String toString() { 084 return "ErodingFactor{" + "factor=" + factor + 085 ", idleHighWaterMark=" + idleHighWaterMark + '}'; 086 } 087 088 /** 089 * Updates internal state using the supplied time and numIdle. 090 * 091 * @param nowMillis 092 * current time 093 * @param numIdle 094 * number of idle elements in the pool 095 */ 096 public void update(final long nowMillis, final int numIdle) { 097 final int idle = Math.max(0, numIdle); 098 idleHighWaterMark = Math.max(idle, idleHighWaterMark); 099 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}