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