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