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 */ 017 018 package org.apache.commons.pool; 019 020 import java.util.Collection; 021 import java.util.Collections; 022 import java.util.HashMap; 023 import java.util.Iterator; 024 import java.util.Map; 025 import java.util.NoSuchElementException; 026 import java.util.Timer; 027 import java.util.TimerTask; 028 029 /** 030 * This class consists exclusively of static methods that operate on or return ObjectPool 031 * or KeyedObjectPool related interfaces. 032 * 033 * @author Sandy McArthur 034 * @version $Revision: 1222670 $ $Date: 2011-12-23 08:18:25 -0500 (Fri, 23 Dec 2011) $ 035 * @since Pool 1.3 036 */ 037 public final class PoolUtils { 038 039 /** 040 * Timer used to periodically check pools idle object count. 041 * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated. 042 */ 043 private static Timer MIN_IDLE_TIMER; //@GuardedBy("this") 044 045 /** 046 * PoolUtils instances should NOT be constructed in standard programming. 047 * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);. 048 * This constructor is public to permit tools that require a JavaBean instance to operate. 049 */ 050 public PoolUtils() { 051 } 052 053 /** 054 * Should the supplied Throwable be re-thrown (eg if it is an instance of 055 * one of the Throwables that should never be swallowed). Used by the pool 056 * error handling for operations that throw exceptions that normally need to 057 * be ignored. 058 * @param t The Throwable to check 059 * @throws ThreadDeath if that is passed in 060 * @throws VirtualMachineError if that is passed in 061 * @since Pool 1.5.5 062 */ 063 public static void checkRethrow(Throwable t) { 064 if (t instanceof ThreadDeath) { 065 throw (ThreadDeath) t; 066 } 067 if (t instanceof VirtualMachineError) { 068 throw (VirtualMachineError) t; 069 } 070 // All other instances of Throwable will be silently swallowed 071 } 072 073 /** 074 * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is 075 * needed. This method is the equivalent of calling 076 * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}. 077 * 078 * @param <V> the type of object 079 * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to. 080 * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key. 081 * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>. 082 * @see #adapt(KeyedPoolableObjectFactory, Object) 083 * @since Pool 1.3 084 */ 085 public static <V> PoolableObjectFactory<V> adapt(final KeyedPoolableObjectFactory<Object, V> keyedFactory) throws IllegalArgumentException { 086 return adapt(keyedFactory, new Object()); 087 } 088 089 /** 090 * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is 091 * needed using the specified <code>key</code> when delegating. 092 * 093 * @param <K> the type of key 094 * @param <V> the type of object 095 * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to. 096 * @param key the key to use when delegating. 097 * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key. 098 * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>. 099 * @see #adapt(KeyedPoolableObjectFactory) 100 * @since Pool 1.3 101 */ 102 public static <K, V> PoolableObjectFactory<V> adapt(final KeyedPoolableObjectFactory<K, V> keyedFactory, final K key) throws IllegalArgumentException { 103 return new PoolableObjectFactoryAdaptor<K, V>(keyedFactory, key); 104 } 105 106 /** 107 * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is 108 * needed. The key is ignored. 109 * 110 * @param <K> the type of key 111 * @param <V> the type of object 112 * @param factory the {@link PoolableObjectFactory} to delegate to. 113 * @return a {@link KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key. 114 * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>. 115 * @since Pool 1.3 116 */ 117 public static <K, V> KeyedPoolableObjectFactory<K, V> adapt(final PoolableObjectFactory<V> factory) throws IllegalArgumentException { 118 return new KeyedPoolableObjectFactoryAdaptor<K, V>(factory); 119 } 120 121 /** 122 * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the 123 * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}. 124 * 125 * @param <V> the type of object 126 * @param keyedPool the {@link KeyedObjectPool} to delegate to. 127 * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with an internal key. 128 * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>. 129 * @see #adapt(KeyedObjectPool, Object) 130 * @since Pool 1.3 131 */ 132 public static <V> ObjectPool<V> adapt(final KeyedObjectPool<Object, V> keyedPool) throws IllegalArgumentException { 133 return adapt(keyedPool, new Object()); 134 } 135 136 /** 137 * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the 138 * specified <code>key</code> when delegating. 139 * 140 * @param <V> the type of object 141 * @param keyedPool the {@link KeyedObjectPool} to delegate to. 142 * @param key the key to use when delegating. 143 * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with the specified key. 144 * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>. 145 * @see #adapt(KeyedObjectPool) 146 * @since Pool 1.3 147 */ 148 public static <V> ObjectPool<V> adapt(final KeyedObjectPool<Object, V> keyedPool, final Object key) throws IllegalArgumentException { 149 return new ObjectPoolAdaptor<V>(keyedPool, key); 150 } 151 152 /** 153 * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed. 154 * The key is ignored. 155 * 156 * @param <K> the type of key 157 * @param <V> the type of object 158 * @param pool the {@link ObjectPool} to delegate to. 159 * @return a {@link KeyedObjectPool} that delegates to <code>pool</code> ignoring the key. 160 * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>. 161 * @since Pool 1.3 162 */ 163 public static <K, V> KeyedObjectPool<K, V> adapt(final ObjectPool<V> pool) throws IllegalArgumentException { 164 return new KeyedObjectPoolAdaptor<K, V>(pool); 165 } 166 167 /** 168 * Wraps an <code>ObjectPool</code> and dynamically checks the type of objects borrowed and returned to the pool. 169 * If an object is passed to the pool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown. 170 * 171 * @param <T> the type of object 172 * @param pool the pool to enforce type safety on 173 * @param type the class type to enforce. 174 * @return an <code>ObjectPool</code> that will only allow objects of <code>type</code> 175 * @since Pool 1.3 176 */ 177 public static <T> ObjectPool<T> checkedPool(final ObjectPool<T> pool, final Class<T> type) { 178 if (pool == null) { 179 throw new IllegalArgumentException("pool must not be null."); 180 } 181 if (type == null) { 182 throw new IllegalArgumentException("type must not be null."); 183 } 184 return new CheckedObjectPool<T>(pool, type); 185 } 186 187 /** 188 * Wraps a <code>KeyedObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool. 189 * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown. 190 * 191 * @param <K> the type of key 192 * @param <V> the type of object 193 * @param keyedPool the keyedPool to enforce type safety on 194 * @param type the class type to enforce. 195 * @return a <code>KeyedObjectPool</code> that will only allow objects of <code>type</code> 196 * @since Pool 1.3 197 */ 198 public static <K, V> KeyedObjectPool<K, V> checkedPool(final KeyedObjectPool<K, V> keyedPool, final Class<V> type) { 199 if (keyedPool == null) { 200 throw new IllegalArgumentException("keyedPool must not be null."); 201 } 202 if (type == null) { 203 throw new IllegalArgumentException("type must not be null."); 204 } 205 return new CheckedKeyedObjectPool<K, V>(keyedPool, type); 206 } 207 208 /** 209 * Periodically check the idle object count for the pool. At most one idle object will be added per period. 210 * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed. 211 * 212 * @param <T> the type of object 213 * @param pool the pool to check periodically. 214 * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object. 215 * @param period the frequency to check the number of idle objects in a pool, see 216 * {@link Timer#schedule(TimerTask, long, long)}. 217 * @return the {@link TimerTask} that will periodically check the pools idle object count. 218 * @throws IllegalArgumentException when <code>pool</code> is <code>null</code> or 219 * when <code>minIdle</code> is negative or when <code>period</code> isn't 220 * valid for {@link Timer#schedule(TimerTask, long, long)}. 221 * @since Pool 1.3 222 */ 223 public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool, final int minIdle, final long period) throws IllegalArgumentException { 224 if (pool == null) { 225 throw new IllegalArgumentException("keyedPool must not be null."); 226 } 227 if (minIdle < 0) { 228 throw new IllegalArgumentException("minIdle must be non-negative."); 229 } 230 final TimerTask task = new ObjectPoolMinIdleTimerTask<T>(pool, minIdle); 231 getMinIdleTimer().schedule(task, 0L, period); 232 return task; 233 } 234 235 /** 236 * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period. 237 * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key 238 * will be performed. 239 * 240 * @param <K> the type of key 241 * @param <V> the type of object 242 * @param keyedPool the keyedPool to check periodically. 243 * @param key the key to check the idle count of. 244 * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object. 245 * @param period the frequency to check the number of idle objects in a keyedPool, see 246 * {@link Timer#schedule(TimerTask, long, long)}. 247 * @return the {@link TimerTask} that will periodically check the pools idle object count. 248 * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or 249 * when <code>minIdle</code> is negative or when <code>period</code> isn't 250 * valid for {@link Timer#schedule(TimerTask, long, long)}. 251 * @since Pool 1.3 252 */ 253 public static <K, V> TimerTask checkMinIdle(final KeyedObjectPool<K, V> keyedPool, final K key, final int minIdle, final long period) throws IllegalArgumentException { 254 if (keyedPool == null) { 255 throw new IllegalArgumentException("keyedPool must not be null."); 256 } 257 if (key == null) { 258 throw new IllegalArgumentException("key must not be null."); 259 } 260 if (minIdle < 0) { 261 throw new IllegalArgumentException("minIdle must be non-negative."); 262 } 263 final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<K, V>(keyedPool, key, minIdle); 264 getMinIdleTimer().schedule(task, 0L, period); 265 return task; 266 } 267 268 /** 269 * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the keyedPool. 270 * At most one idle object will be added per period. 271 * 272 * @param <K> the type of key 273 * @param <V> the type of object 274 * @param keyedPool the keyedPool to check periodically. 275 * @param keys a collection of keys to check the idle object count. 276 * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object. 277 * @param period the frequency to check the number of idle objects in a keyedPool, see 278 * {@link Timer#schedule(TimerTask, long, long)}. 279 * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count. 280 * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the 281 * collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't 282 * valid for {@link Timer#schedule(TimerTask, long, long)}. 283 * @see #checkMinIdle(KeyedObjectPool, Object, int, long) 284 * @since Pool 1.3 285 */ 286 public static <K, V> Map<K, TimerTask> checkMinIdle(final KeyedObjectPool<K, V> keyedPool, final Collection<? extends K> keys, final int minIdle, final long period) throws IllegalArgumentException { 287 if (keys == null) { 288 throw new IllegalArgumentException("keys must not be null."); 289 } 290 final Map<K, TimerTask> tasks = new HashMap<K, TimerTask>(keys.size()); 291 final Iterator<? extends K> iter = keys.iterator(); 292 while (iter.hasNext()) { 293 final K key = iter.next(); 294 final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period); 295 tasks.put(key, task); 296 } 297 return tasks; 298 } 299 300 /** 301 * Call <code>addObject()</code> on <code>pool</code> <code>count</code> number of times. 302 * 303 * @param <T> the type of object 304 * @param pool the pool to prefill. 305 * @param count the number of idle objects to add. 306 * @throws Exception when {@link ObjectPool#addObject()} fails. 307 * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>. 308 * @since Pool 1.3 309 */ 310 public static <T> void prefill(final ObjectPool<T> pool, final int count) throws Exception, IllegalArgumentException { 311 if (pool == null) { 312 throw new IllegalArgumentException("pool must not be null."); 313 } 314 for (int i = 0; i < count; i++) { 315 pool.addObject(); 316 } 317 } 318 319 /** 320 * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code> 321 * number of times. 322 * 323 * @param <K> the type of key 324 * @param <V> the type of object 325 * @param keyedPool the keyedPool to prefill. 326 * @param key the key to add objects for. 327 * @param count the number of idle objects to add for <code>key</code>. 328 * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails. 329 * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>. 330 * @since Pool 1.3 331 */ 332 public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool, final K key, final int count) throws Exception, IllegalArgumentException { 333 if (keyedPool == null) { 334 throw new IllegalArgumentException("keyedPool must not be null."); 335 } 336 if (key == null) { 337 throw new IllegalArgumentException("key must not be null."); 338 } 339 for (int i = 0; i < count; i++) { 340 keyedPool.addObject(key); 341 } 342 } 343 344 /** 345 * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for 346 * <code>count</code> number of times. This has the same effect as calling 347 * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection. 348 * 349 * @param <K> the type of key 350 * @param <V> the type of object 351 * @param keyedPool the keyedPool to prefill. 352 * @param keys {@link Collection} of keys to add objects for. 353 * @param count the number of idle objects to add for each <code>key</code>. 354 * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails. 355 * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or 356 * any value in <code>keys</code> is <code>null</code>. 357 * @see #prefill(KeyedObjectPool, Object, int) 358 * @since Pool 1.3 359 */ 360 public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool, final Collection<? extends K> keys, final int count) throws Exception, IllegalArgumentException { 361 if (keys == null) { 362 throw new IllegalArgumentException("keys must not be null."); 363 } 364 final Iterator<? extends K> iter = keys.iterator(); 365 while (iter.hasNext()) { 366 prefill(keyedPool, iter.next(), count); 367 } 368 } 369 370 /** 371 * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool. 372 * 373 * <p><b>Note:</b> 374 * This should not be used on pool implementations that already provide proper synchronization 375 * such as the pools provided in the Commons Pool library. Wrapping a pool that 376 * {@link #wait() waits} for poolable objects to be returned before allowing another one to be 377 * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. 378 * </p> 379 * 380 * @param <T> the type of object 381 * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. 382 * @return a synchronized view of the specified ObjectPool. 383 * @since Pool 1.3 384 */ 385 public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) { 386 if (pool == null) { 387 throw new IllegalArgumentException("pool must not be null."); 388 } 389 /* 390 assert !(pool instanceof GenericObjectPool) 391 : "GenericObjectPool is already thread-safe"; 392 assert !(pool instanceof SoftReferenceObjectPool) 393 : "SoftReferenceObjectPool is already thread-safe"; 394 assert !(pool instanceof StackObjectPool) 395 : "StackObjectPool is already thread-safe"; 396 assert !"org.apache.commons.pool.composite.CompositeObjectPool".equals(pool.getClass().getName()) 397 : "CompositeObjectPools are already thread-safe"; 398 */ 399 return new SynchronizedObjectPool<T>(pool); 400 } 401 402 /** 403 * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. 404 * 405 * <p><b>Note:</b> 406 * This should not be used on pool implementations that already provide proper synchronization 407 * such as the pools provided in the Commons Pool library. Wrapping a pool that 408 * {@link #wait() waits} for poolable objects to be returned before allowing another one to be 409 * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. 410 * </p> 411 * 412 * @param <K> the type of key 413 * @param <V> the type of object 414 * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool. 415 * @return a synchronized view of the specified KeyedObjectPool. 416 * @since Pool 1.3 417 */ 418 public static <K, V> KeyedObjectPool<K, V> synchronizedPool(final KeyedObjectPool<K, V> keyedPool) { 419 if (keyedPool == null) { 420 throw new IllegalArgumentException("keyedPool must not be null."); 421 } 422 /* 423 assert !(keyedPool instanceof GenericKeyedObjectPool) 424 : "GenericKeyedObjectPool is already thread-safe"; 425 assert !(keyedPool instanceof StackKeyedObjectPool) 426 : "StackKeyedObjectPool is already thread-safe"; 427 assert !"org.apache.commons.pool.composite.CompositeKeyedObjectPool".equals(keyedPool.getClass().getName()) 428 : "CompositeKeyedObjectPools are already thread-safe"; 429 */ 430 return new SynchronizedKeyedObjectPool<K, V>(keyedPool); 431 } 432 433 /** 434 * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory. 435 * 436 * @param <T> the type of object 437 * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory. 438 * @return a synchronized view of the specified PoolableObjectFactory. 439 * @since Pool 1.3 440 */ 441 public static <T> PoolableObjectFactory<T> synchronizedPoolableFactory(final PoolableObjectFactory<T> factory) { 442 return new SynchronizedPoolableObjectFactory<T>(factory); 443 } 444 445 /** 446 * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory. 447 * 448 * @param <K> the type of key 449 * @param <V> the type of object 450 * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory. 451 * @return a synchronized view of the specified KeyedPoolableObjectFactory. 452 * @since Pool 1.3 453 */ 454 public static <K, V> KeyedPoolableObjectFactory<K, V> synchronizedPoolableFactory(final KeyedPoolableObjectFactory<K, V> keyedFactory) { 455 return new SynchronizedKeyedPoolableObjectFactory<K, V>(keyedFactory); 456 } 457 458 /** 459 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. 460 * This is intended as an always thread-safe alternative to using an idle object evictor 461 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered 462 * pools that experience load spikes. 463 * 464 * @param <T> the type of object 465 * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible. 466 * @return a pool that adaptively decreases it's size when idle objects are no longer needed. 467 * @see #erodingPool(ObjectPool, float) 468 * @since Pool 1.4 469 */ 470 public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) { 471 return erodingPool(pool, 1f); 472 } 473 474 /** 475 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. 476 * This is intended as an always thread-safe alternative to using an idle object evictor 477 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered 478 * pools that experience load spikes. 479 * 480 * <p> 481 * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink 482 * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. 483 * Values greater than 1 cause the pool to less frequently try to shrink it's size. 484 * </p> 485 * 486 * @param <T> the type of object 487 * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible. 488 * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. 489 * If 0 < factor < 1 then the pool shrinks more aggressively. 490 * If 1 < factor then the pool shrinks less aggressively. 491 * @return a pool that adaptively decreases it's size when idle objects are no longer needed. 492 * @see #erodingPool(ObjectPool) 493 * @since Pool 1.4 494 */ 495 public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool, final float factor) { 496 if (pool == null) { 497 throw new IllegalArgumentException("pool must not be null."); 498 } 499 if (factor <= 0f) { 500 throw new IllegalArgumentException("factor must be positive."); 501 } 502 return new ErodingObjectPool<T>(pool, factor); 503 } 504 505 /** 506 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. 507 * This is intended as an always thread-safe alternative to using an idle object evictor 508 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered 509 * pools that experience load spikes. 510 * 511 * @param <K> the type of key 512 * @param <V> the type of object 513 * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when 514 * possible. 515 * @return a pool that adaptively decreases it's size when idle objects are no longer needed. 516 * @see #erodingPool(KeyedObjectPool, float) 517 * @see #erodingPool(KeyedObjectPool, float, boolean) 518 * @since Pool 1.4 519 */ 520 public static <K, V> KeyedObjectPool<K, V> erodingPool(final KeyedObjectPool<K, V> keyedPool) { 521 return erodingPool(keyedPool, 1f); 522 } 523 524 /** 525 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. 526 * This is intended as an always thread-safe alternative to using an idle object evictor 527 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered 528 * pools that experience load spikes. 529 * 530 * <p> 531 * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink 532 * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. 533 * Values greater than 1 cause the pool to less frequently try to shrink it's size. 534 * </p> 535 * 536 * @param <K> the type of key 537 * @param <V> the type of object 538 * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when 539 * possible. 540 * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. 541 * If 0 < factor < 1 then the pool shrinks more aggressively. 542 * If 1 < factor then the pool shrinks less aggressively. 543 * @return a pool that adaptively decreases it's size when idle objects are no longer needed. 544 * @see #erodingPool(KeyedObjectPool, float, boolean) 545 * @since Pool 1.4 546 */ 547 public static <K, V> KeyedObjectPool<K, V> erodingPool(final KeyedObjectPool<K, V> keyedPool, final float factor) { 548 return erodingPool(keyedPool, factor, false); 549 } 550 551 /** 552 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. 553 * This is intended as an always thread-safe alternative to using an idle object evictor 554 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered 555 * pools that experience load spikes. 556 * 557 * <p> 558 * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink 559 * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. 560 * Values greater than 1 cause the pool to less frequently try to shrink it's size. 561 * </p> 562 * 563 * <p> 564 * The perKey parameter determines if the pool shrinks on a whole pool basis or a per key basis. 565 * When perKey is false, the keys do not have an effect on the rate at which the pool tries to 566 * shrink it's size. When perKey is true, each key is shrunk independently. 567 * </p> 568 * 569 * @param <K> the type of key 570 * @param <V> the type of object 571 * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when 572 * possible. 573 * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. 574 * If 0 < factor < 1 then the pool shrinks more aggressively. 575 * If 1 < factor then the pool shrinks less aggressively. 576 * @param perKey when true, each key is treated independently. 577 * @return a pool that adaptively decreases it's size when idle objects are no longer needed. 578 * @see #erodingPool(KeyedObjectPool) 579 * @see #erodingPool(KeyedObjectPool, float) 580 * @since Pool 1.4 581 */ 582 public static <K, V> KeyedObjectPool<K, V> erodingPool(final KeyedObjectPool<K, V> keyedPool, final float factor, final boolean perKey) { 583 if (keyedPool == null) { 584 throw new IllegalArgumentException("keyedPool must not be null."); 585 } 586 if (factor <= 0f) { 587 throw new IllegalArgumentException("factor must be positive."); 588 } 589 if (perKey) { 590 return new ErodingPerKeyKeyedObjectPool<K, V>(keyedPool, factor); 591 } else { 592 return new ErodingKeyedObjectPool<K, V>(keyedPool, factor); 593 } 594 } 595 596 /** 597 * Get the <code>Timer</code> for checking keyedPool's idle count. Lazily create the {@link Timer} as needed. 598 * 599 * @return the {@link Timer} for checking keyedPool's idle count. 600 * @since Pool 1.3 601 */ 602 private static synchronized Timer getMinIdleTimer() { 603 if (MIN_IDLE_TIMER == null) { 604 MIN_IDLE_TIMER = new Timer(true); 605 } 606 return MIN_IDLE_TIMER; 607 } 608 609 /** 610 * Adaptor class that wraps and converts a KeyedPoolableObjectFactory with a fixed 611 * key to a PoolableObjectFactory. 612 */ 613 private static class PoolableObjectFactoryAdaptor<K, V> implements PoolableObjectFactory<V> { 614 /** Fixed key */ 615 private final K key; 616 617 /** Wrapped factory */ 618 private final KeyedPoolableObjectFactory<K, V> keyedFactory; 619 620 /** 621 * Create a PoolableObjectFactoryAdaptor wrapping the provided KeyedPoolableObjectFactory with the 622 * given fixed key. 623 * 624 * @param keyedFactory KeyedPoolableObjectFactory that will manage objects 625 * @param key fixed key 626 * @throws IllegalArgumentException if either of the parameters is null 627 */ 628 PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory<K, V> keyedFactory, final K key) 629 throws IllegalArgumentException { 630 if (keyedFactory == null) { 631 throw new IllegalArgumentException("keyedFactory must not be null."); 632 } 633 if (key == null) { 634 throw new IllegalArgumentException("key must not be null."); 635 } 636 this.keyedFactory = keyedFactory; 637 this.key = key; 638 } 639 640 /** 641 * Create an object instance using the configured factory and key. 642 * 643 * @return new object instance 644 */ 645 public V makeObject() throws Exception { 646 return keyedFactory.makeObject(key); 647 } 648 649 /** 650 * Destroy the object, passing the fixed key to the factory. 651 * 652 * @param obj object to destroy 653 */ 654 public void destroyObject(final V obj) throws Exception { 655 keyedFactory.destroyObject(key, obj); 656 } 657 658 /** 659 * Validate the object, passing the fixed key to the factory. 660 * 661 * @param obj object to validate 662 * @return true if validation is successful 663 */ 664 public boolean validateObject(final V obj) { 665 return keyedFactory.validateObject(key, obj); 666 } 667 668 /** 669 * Activate the object, passing the fixed key to the factory. 670 * 671 * @param obj object to activate 672 */ 673 public void activateObject(final V obj) throws Exception { 674 keyedFactory.activateObject(key, obj); 675 } 676 677 /** 678 * Passivate the object, passing the fixed key to the factory. 679 * 680 * @param obj object to passivate 681 */ 682 public void passivateObject(final V obj) throws Exception { 683 keyedFactory.passivateObject(key, obj); 684 } 685 686 /** 687 * {@inheritDoc} 688 */ 689 @Override 690 public String toString() { 691 final StringBuffer sb = new StringBuffer(); 692 sb.append("PoolableObjectFactoryAdaptor"); 693 sb.append("{key=").append(key); 694 sb.append(", keyedFactory=").append(keyedFactory); 695 sb.append('}'); 696 return sb.toString(); 697 } 698 } 699 700 /** 701 * Adaptor class that turns a PoolableObjectFactory into a KeyedPoolableObjectFactory by 702 * ignoring keys. 703 */ 704 private static class KeyedPoolableObjectFactoryAdaptor<K, V> implements KeyedPoolableObjectFactory<K, V> { 705 706 /** Underlying PoolableObjectFactory */ 707 private final PoolableObjectFactory<V> factory; 708 709 /** 710 * Create a new KeyedPoolableObjectFactoryAdaptor using the given PoolableObjectFactory to 711 * manage objects. 712 * 713 * @param factory wrapped PoolableObjectFactory 714 * @throws IllegalArgumentException if the factory is null 715 */ 716 KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory<V> factory) throws IllegalArgumentException { 717 if (factory == null) { 718 throw new IllegalArgumentException("factory must not be null."); 719 } 720 this.factory = factory; 721 } 722 723 /** 724 * Create a new object instance, ignoring the key 725 * 726 * @param key ignored 727 * @return newly created object instance 728 */ 729 public V makeObject(final K key) throws Exception { 730 return factory.makeObject(); 731 } 732 733 /** 734 * Destroy the object, ignoring the key. 735 * 736 * @param key ignored 737 * @param obj instance to destroy 738 */ 739 public void destroyObject(final K key, final V obj) throws Exception { 740 factory.destroyObject(obj); 741 } 742 743 /** 744 * Validate the object, ignoring the key 745 * 746 * @param key ignored 747 * @param obj object to validate 748 * @return true if validation is successful 749 */ 750 public boolean validateObject(final K key, final V obj) { 751 return factory.validateObject(obj); 752 } 753 754 /** 755 * Activate the object, ignoring the key. 756 * 757 * @param key ignored 758 * @param obj object to be activated 759 */ 760 public void activateObject(final K key, final V obj) throws Exception { 761 factory.activateObject(obj); 762 } 763 764 /** 765 * Passivate the object, ignoring the key. 766 * 767 * @param key ignored 768 * @param obj object to passivate 769 */ 770 public void passivateObject(final K key, final V obj) throws Exception { 771 factory.passivateObject(obj); 772 } 773 774 /** 775 * {@inheritDoc} 776 */ 777 @Override 778 public String toString() { 779 final StringBuffer sb = new StringBuffer(); 780 sb.append("KeyedPoolableObjectFactoryAdaptor"); 781 sb.append("{factory=").append(factory); 782 sb.append('}'); 783 return sb.toString(); 784 } 785 } 786 787 /** 788 * Adapts a KeyedObjectPool to make it an ObjectPool by fixing restricting to 789 * a fixed key. 790 */ 791 private static class ObjectPoolAdaptor<V> implements ObjectPool<V> { 792 793 /** Fixed key */ 794 private final Object key; 795 796 /** Underlying KeyedObjectPool */ 797 private final KeyedObjectPool<Object, V> keyedPool; 798 799 /** 800 * Create a new ObjectPoolAdaptor using the provided KeyedObjectPool and fixed key. 801 * 802 * @param keyedPool underlying KeyedObjectPool 803 * @param key fixed key 804 * @throws IllegalArgumentException if either of the parameters is null 805 */ 806 ObjectPoolAdaptor(final KeyedObjectPool<Object, V> keyedPool, final Object key) throws IllegalArgumentException { 807 if (keyedPool == null) { 808 throw new IllegalArgumentException("keyedPool must not be null."); 809 } 810 if (key == null) { 811 throw new IllegalArgumentException("key must not be null."); 812 } 813 this.keyedPool = keyedPool; 814 this.key = key; 815 } 816 817 /** 818 * {@inheritDoc} 819 */ 820 public V borrowObject() throws Exception, NoSuchElementException, IllegalStateException { 821 return keyedPool.borrowObject(key); 822 } 823 824 /** 825 * {@inheritDoc} 826 */ 827 public void returnObject(final V obj) { 828 try { 829 keyedPool.returnObject(key, obj); 830 } catch (Exception e) { 831 // swallowed as of Pool 2 832 } 833 } 834 835 /** 836 * {@inheritDoc} 837 */ 838 public void invalidateObject(final V obj) { 839 try { 840 keyedPool.invalidateObject(key, obj); 841 } catch (Exception e) { 842 // swallowed as of Pool 2 843 } 844 } 845 846 /** 847 * {@inheritDoc} 848 */ 849 public void addObject() throws Exception, IllegalStateException { 850 keyedPool.addObject(key); 851 } 852 853 /** 854 * {@inheritDoc} 855 */ 856 public int getNumIdle() throws UnsupportedOperationException { 857 return keyedPool.getNumIdle(key); 858 } 859 860 /** 861 * {@inheritDoc} 862 */ 863 public int getNumActive() throws UnsupportedOperationException { 864 return keyedPool.getNumActive(key); 865 } 866 867 /** 868 * {@inheritDoc} 869 */ 870 public void clear() throws Exception, UnsupportedOperationException { 871 keyedPool.clear(); 872 } 873 874 /** 875 * {@inheritDoc} 876 */ 877 public void close() { 878 try { 879 keyedPool.close(); 880 } catch (Exception e) { 881 // swallowed as of Pool 2 882 } 883 } 884 885 /** 886 * Sets the PoolableObjectFactory for the pool. 887 * 888 * @param factory new PoolableObjectFactory 889 * @deprecated to be removed in version 2.0 890 */ 891 @Deprecated 892 public void setFactory(final PoolableObjectFactory<V> factory) throws IllegalStateException, UnsupportedOperationException { 893 keyedPool.setFactory(adapt(factory)); 894 } 895 896 /** 897 * {@inheritDoc} 898 */ 899 @Override 900 public String toString() { 901 final StringBuffer sb = new StringBuffer(); 902 sb.append("ObjectPoolAdaptor"); 903 sb.append("{key=").append(key); 904 sb.append(", keyedPool=").append(keyedPool); 905 sb.append('}'); 906 return sb.toString(); 907 } 908 } 909 910 /** 911 * Adapts an ObjectPool to implement KeyedObjectPool by ignoring key arguments. 912 */ 913 private static class KeyedObjectPoolAdaptor<K, V> implements KeyedObjectPool<K, V> { 914 915 /** Underlying pool */ 916 private final ObjectPool<V> pool; 917 918 /** 919 * Create a new KeyedObjectPoolAdaptor wrapping the given ObjectPool 920 * 921 * @param pool underlying object pool 922 * @throws IllegalArgumentException if pool is null 923 */ 924 KeyedObjectPoolAdaptor(final ObjectPool<V> pool) throws IllegalArgumentException { 925 if (pool == null) { 926 throw new IllegalArgumentException("pool must not be null."); 927 } 928 this.pool = pool; 929 } 930 931 /** 932 * Borrow and object from the pool, ignoring the key 933 * 934 * @param key ignored 935 * @return newly created object instance 936 */ 937 public V borrowObject(final K key) throws Exception, NoSuchElementException, IllegalStateException { 938 return pool.borrowObject(); 939 } 940 941 /** 942 * Return and object to the pool, ignoring the key 943 * 944 * @param key ignored 945 * @param obj object to return 946 */ 947 public void returnObject(final K key, final V obj) { 948 try { 949 pool.returnObject(obj); 950 } catch (Exception e) { 951 // swallowed as of Pool 2 952 } 953 } 954 955 /** 956 * Invalidate and object, ignoring the key 957 * 958 * @param obj object to invalidate 959 * @param key ignored 960 */ 961 public void invalidateObject(final K key, final V obj) { 962 try { 963 pool.invalidateObject(obj); 964 } catch (Exception e) { 965 // swallowed as of Pool 2 966 } 967 } 968 969 /** 970 * Add an object to the pool, ignoring the key 971 * 972 * @param key ignored 973 */ 974 public void addObject(final K key) throws Exception, IllegalStateException { 975 pool.addObject(); 976 } 977 978 /** 979 * Return the number of objects idle in the pool, ignoring the key. 980 * 981 * @param key ignored 982 * @return idle instance count 983 */ 984 public int getNumIdle(final K key) throws UnsupportedOperationException { 985 return pool.getNumIdle(); 986 } 987 988 /** 989 * Return the number of objects checked out from the pool, ignoring the key. 990 * 991 * @param key ignored 992 * @return active instance count 993 */ 994 public int getNumActive(final K key) throws UnsupportedOperationException { 995 return pool.getNumActive(); 996 } 997 998 /** 999 * {@inheritDoc} 1000 */ 1001 public int getNumIdle() throws UnsupportedOperationException { 1002 return pool.getNumIdle(); 1003 } 1004 1005 /** 1006 * {@inheritDoc} 1007 */ 1008 public int getNumActive() throws UnsupportedOperationException { 1009 return pool.getNumActive(); 1010 } 1011 1012 /** 1013 * {@inheritDoc} 1014 */ 1015 public void clear() throws Exception, UnsupportedOperationException { 1016 pool.clear(); 1017 } 1018 1019 /** 1020 * Clear the pool, ignoring the key (has same effect as {@link #clear()}. 1021 * 1022 * @param key ignored. 1023 */ 1024 public void clear(final K key) throws Exception, UnsupportedOperationException { 1025 pool.clear(); 1026 } 1027 1028 /** 1029 * {@inheritDoc} 1030 */ 1031 public void close() { 1032 try { 1033 pool.close(); 1034 } catch (Exception e) { 1035 // swallowed as of Pool 2 1036 } 1037 } 1038 1039 /** 1040 * Sets the factory used to manage objects. 1041 * 1042 * @param factory new factory to use managing object instances 1043 * @deprecated to be removed in version 2.0 1044 */ 1045 @Deprecated 1046 @SuppressWarnings("unchecked") 1047 public void setFactory(final KeyedPoolableObjectFactory<K, V> factory) throws IllegalStateException, UnsupportedOperationException { 1048 pool.setFactory(adapt((KeyedPoolableObjectFactory<Object, V>)factory)); 1049 } 1050 1051 /** 1052 * {@inheritDoc} 1053 */ 1054 @Override 1055 public String toString() { 1056 final StringBuffer sb = new StringBuffer(); 1057 sb.append("KeyedObjectPoolAdaptor"); 1058 sb.append("{pool=").append(pool); 1059 sb.append('}'); 1060 return sb.toString(); 1061 } 1062 } 1063 1064 /** 1065 * An object pool that performs type checking on objects passed 1066 * to pool methods. 1067 * 1068 */ 1069 private static class CheckedObjectPool<T> implements ObjectPool<T> { 1070 /** 1071 * Type of objects allowed in the pool. This should be a subtype of the return type of 1072 * the underlying pool's associated object factory. 1073 */ 1074 private final Class<T> type; 1075 1076 /** Underlying object pool */ 1077 private final ObjectPool<T> pool; 1078 1079 /** 1080 * Create a CheckedObjectPool accepting objects of the given type using 1081 * the given pool. 1082 * 1083 * @param pool underlying object pool 1084 * @param type expected pooled object type 1085 * @throws IllegalArgumentException if either parameter is null 1086 */ 1087 CheckedObjectPool(final ObjectPool<T> pool, final Class<T> type) { 1088 if (pool == null) { 1089 throw new IllegalArgumentException("pool must not be null."); 1090 } 1091 if (type == null) { 1092 throw new IllegalArgumentException("type must not be null."); 1093 } 1094 this.pool = pool; 1095 this.type = type; 1096 } 1097 1098 /** 1099 * Borrow an object from the pool, checking its type. 1100 * 1101 * @return a type-checked object from the pool 1102 * @throws ClassCastException if the object returned by the pool is not of the expected type 1103 */ 1104 public T borrowObject() throws Exception, NoSuchElementException, IllegalStateException { 1105 final T obj = pool.borrowObject(); 1106 if (type.isInstance(obj)) { 1107 return obj; 1108 } else { 1109 throw new ClassCastException("Borrowed object is not of type: " + type.getName() + " was: " + obj); 1110 } 1111 } 1112 1113 /** 1114 * Return an object to the pool, verifying that it is of the correct type. 1115 * 1116 * @param obj object to return 1117 * @throws ClassCastException if obj is not of the expected type 1118 */ 1119 public void returnObject(final T obj) { 1120 if (type.isInstance(obj)) { 1121 try { 1122 pool.returnObject(obj); 1123 } catch (Exception e) { 1124 // swallowed as of Pool 2 1125 } 1126 } else { 1127 throw new ClassCastException("Returned object is not of type: " + type.getName() + " was: " + obj); 1128 } 1129 } 1130 1131 /** 1132 * Invalidates an object from the pool, verifying that it is of the expected type. 1133 * 1134 * @param obj object to invalidate 1135 * @throws ClassCastException if obj is not of the expected type 1136 */ 1137 public void invalidateObject(final T obj) { 1138 if (type.isInstance(obj)) { 1139 try { 1140 pool.invalidateObject(obj); 1141 } catch (Exception e) { 1142 // swallowed as of Pool 2 1143 } 1144 } else { 1145 throw new ClassCastException("Invalidated object is not of type: " + type.getName() + " was: " + obj); 1146 } 1147 } 1148 1149 /** 1150 * {@inheritDoc} 1151 */ 1152 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { 1153 pool.addObject(); 1154 } 1155 1156 /** 1157 * {@inheritDoc} 1158 */ 1159 public int getNumIdle() throws UnsupportedOperationException { 1160 return pool.getNumIdle(); 1161 } 1162 1163 /** 1164 * {@inheritDoc} 1165 */ 1166 public int getNumActive() throws UnsupportedOperationException { 1167 return pool.getNumActive(); 1168 } 1169 1170 /** 1171 * {@inheritDoc} 1172 */ 1173 public void clear() throws Exception, UnsupportedOperationException { 1174 pool.clear(); 1175 } 1176 1177 /** 1178 * {@inheritDoc} 1179 */ 1180 public void close() { 1181 try { 1182 pool.close(); 1183 } catch (Exception e) { 1184 // swallowed as of Pool 2 1185 } 1186 } 1187 1188 /** 1189 * Sets the object factory associated with the pool 1190 * 1191 * @param factory object factory 1192 * @deprecated to be removed in version 2.0 1193 */ 1194 @Deprecated 1195 public void setFactory(final PoolableObjectFactory<T> factory) throws IllegalStateException, UnsupportedOperationException { 1196 pool.setFactory(factory); 1197 } 1198 1199 /** 1200 * {@inheritDoc} 1201 */ 1202 @Override 1203 public String toString() { 1204 final StringBuffer sb = new StringBuffer(); 1205 sb.append("CheckedObjectPool"); 1206 sb.append("{type=").append(type); 1207 sb.append(", pool=").append(pool); 1208 sb.append('}'); 1209 return sb.toString(); 1210 } 1211 } 1212 1213 /** 1214 * A keyed object pool that performs type checking on objects passed 1215 * to pool methods. 1216 * 1217 */ 1218 private static class CheckedKeyedObjectPool<K, V> implements KeyedObjectPool<K, V> { 1219 /** 1220 * Expected type of objects managed by the pool. This should be 1221 * a subtype of the return type of the object factory used by the pool. 1222 */ 1223 private final Class<V> type; 1224 1225 /** Underlying pool */ 1226 private final KeyedObjectPool<K, V> keyedPool; 1227 1228 /** 1229 * Create a new CheckedKeyedObjectPool from the given pool with given expected object type. 1230 * 1231 * @param keyedPool underlying pool 1232 * @param type expected object type 1233 * @throws IllegalArgumentException if either parameter is null 1234 */ 1235 CheckedKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final Class<V> type) { 1236 if (keyedPool == null) { 1237 throw new IllegalArgumentException("keyedPool must not be null."); 1238 } 1239 if (type == null) { 1240 throw new IllegalArgumentException("type must not be null."); 1241 } 1242 this.keyedPool = keyedPool; 1243 this.type = type; 1244 } 1245 1246 /** 1247 * Borrow an object from the pool, verifying correct return type. 1248 * 1249 * @param key pool key 1250 * @return type-checked object from the pool under the given key 1251 * @throws ClassCastException if the object returned by the pool is not of the expected type 1252 */ 1253 public V borrowObject(final K key) throws Exception, NoSuchElementException, IllegalStateException { 1254 V obj = keyedPool.borrowObject(key); 1255 if (type.isInstance(obj)) { 1256 return obj; 1257 } else { 1258 throw new ClassCastException("Borrowed object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); 1259 } 1260 } 1261 1262 /** 1263 * Return an object to the pool, checking its type. 1264 * 1265 * @param key the associated key (not type-checked) 1266 * @param obj the object to return (type-checked) 1267 * @throws ClassCastException if obj is not of the expected type 1268 */ 1269 public void returnObject(final K key, final V obj) { 1270 if (type.isInstance(obj)) { 1271 try { 1272 keyedPool.returnObject(key, obj); 1273 } catch (Exception e) { 1274 // swallowed as of Pool 2 1275 } 1276 } else { 1277 throw new ClassCastException("Returned object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); 1278 } 1279 } 1280 1281 /** 1282 * Invalidate an object to the pool, checking its type. 1283 * 1284 * @param key the associated key (not type-checked) 1285 * @param obj the object to return (type-checked) 1286 * @throws ClassCastException if obj is not of the expected type 1287 */ 1288 public void invalidateObject(final K key, final V obj) { 1289 if (type.isInstance(obj)) { 1290 try { 1291 keyedPool.invalidateObject(key, obj); 1292 } catch (Exception e) { 1293 // swallowed as of Pool 2 1294 } 1295 } else { 1296 throw new ClassCastException("Invalidated object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); 1297 } 1298 } 1299 1300 /** 1301 * {@inheritDoc} 1302 */ 1303 public void addObject(final K key) throws Exception, IllegalStateException, UnsupportedOperationException { 1304 keyedPool.addObject(key); 1305 } 1306 1307 /** 1308 * {@inheritDoc} 1309 */ 1310 public int getNumIdle(final K key) throws UnsupportedOperationException { 1311 return keyedPool.getNumIdle(key); 1312 } 1313 1314 /** 1315 * {@inheritDoc} 1316 */ 1317 public int getNumActive(final K key) throws UnsupportedOperationException { 1318 return keyedPool.getNumActive(key); 1319 } 1320 1321 /** 1322 * {@inheritDoc} 1323 */ 1324 public int getNumIdle() throws UnsupportedOperationException { 1325 return keyedPool.getNumIdle(); 1326 } 1327 1328 /** 1329 * {@inheritDoc} 1330 */ 1331 public int getNumActive() throws UnsupportedOperationException { 1332 return keyedPool.getNumActive(); 1333 } 1334 1335 /** 1336 * {@inheritDoc} 1337 */ 1338 public void clear() throws Exception, UnsupportedOperationException { 1339 keyedPool.clear(); 1340 } 1341 1342 /** 1343 * {@inheritDoc} 1344 */ 1345 public void clear(final K key) throws Exception, UnsupportedOperationException { 1346 keyedPool.clear(key); 1347 } 1348 1349 /** 1350 * {@inheritDoc} 1351 */ 1352 public void close() { 1353 try { 1354 keyedPool.close(); 1355 } catch (Exception e) { 1356 // swallowed as of Pool 2 1357 } 1358 } 1359 1360 /** 1361 * Sets the object factory associated with the pool 1362 * 1363 * @param factory object factory 1364 * @deprecated to be removed in version 2.0 1365 */ 1366 @Deprecated 1367 public void setFactory(final KeyedPoolableObjectFactory<K, V> factory) throws IllegalStateException, UnsupportedOperationException { 1368 keyedPool.setFactory(factory); 1369 } 1370 1371 /** 1372 * {@inheritDoc} 1373 */ 1374 @Override 1375 public String toString() { 1376 final StringBuffer sb = new StringBuffer(); 1377 sb.append("CheckedKeyedObjectPool"); 1378 sb.append("{type=").append(type); 1379 sb.append(", keyedPool=").append(keyedPool); 1380 sb.append('}'); 1381 return sb.toString(); 1382 } 1383 } 1384 1385 /** 1386 * Timer task that adds objects to the pool until the number of idle 1387 * instances reaches the configured minIdle. Note that this is not the 1388 * same as the pool's minIdle setting. 1389 * 1390 */ 1391 private static class ObjectPoolMinIdleTimerTask<T> extends TimerTask { 1392 1393 /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ 1394 private final int minIdle; 1395 1396 /** Object pool */ 1397 private final ObjectPool<T> pool; 1398 1399 /** 1400 * Create a new ObjectPoolMinIdleTimerTask for the given pool with the given minIdle setting. 1401 * 1402 * @param pool object pool 1403 * @param minIdle number of idle instances to maintain 1404 * @throws IllegalArgumentException if the pool is null 1405 */ 1406 ObjectPoolMinIdleTimerTask(final ObjectPool<T> pool, final int minIdle) throws IllegalArgumentException { 1407 if (pool == null) { 1408 throw new IllegalArgumentException("pool must not be null."); 1409 } 1410 this.pool = pool; 1411 this.minIdle = minIdle; 1412 } 1413 1414 /** 1415 * {@inheritDoc} 1416 */ 1417 @Override 1418 public void run() { 1419 boolean success = false; 1420 try { 1421 if (pool.getNumIdle() < minIdle) { 1422 pool.addObject(); 1423 } 1424 success = true; 1425 1426 } catch (Exception e) { 1427 cancel(); 1428 1429 } finally { 1430 // detect other types of Throwable and cancel this Timer 1431 if (!success) { 1432 cancel(); 1433 } 1434 } 1435 } 1436 1437 /** 1438 * {@inheritDoc} 1439 */ 1440 @Override 1441 public String toString() { 1442 final StringBuffer sb = new StringBuffer(); 1443 sb.append("ObjectPoolMinIdleTimerTask"); 1444 sb.append("{minIdle=").append(minIdle); 1445 sb.append(", pool=").append(pool); 1446 sb.append('}'); 1447 return sb.toString(); 1448 } 1449 } 1450 1451 /** 1452 * Timer task that adds objects to the pool until the number of idle 1453 * instances for the given key reaches the configured minIdle. Note that this is not the 1454 * same as the pool's minIdle setting. 1455 * 1456 */ 1457 private static class KeyedObjectPoolMinIdleTimerTask<K, V> extends TimerTask { 1458 /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ 1459 private final int minIdle; 1460 1461 /** Key to ensure minIdle for */ 1462 private final K key; 1463 1464 /** Keyed object pool */ 1465 private final KeyedObjectPool<K, V> keyedPool; 1466 1467 /** 1468 * Create a new KeyedObjecPoolMinIdleTimerTask. 1469 * 1470 * @param keyedPool keyed object pool 1471 * @param key key to ensure minimum number of idle instances 1472 * @param minIdle minimum number of idle instances 1473 * @throws IllegalArgumentException if the key is null 1474 */ 1475 KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool<K, V> keyedPool, final K key, final int minIdle) throws IllegalArgumentException { 1476 if (keyedPool == null) { 1477 throw new IllegalArgumentException("keyedPool must not be null."); 1478 } 1479 this.keyedPool = keyedPool; 1480 this.key = key; 1481 this.minIdle = minIdle; 1482 } 1483 1484 /** 1485 * {@inheritDoc} 1486 */ 1487 @Override 1488 public void run() { 1489 boolean success = false; 1490 try { 1491 if (keyedPool.getNumIdle(key) < minIdle) { 1492 keyedPool.addObject(key); 1493 } 1494 success = true; 1495 1496 } catch (Exception e) { 1497 cancel(); 1498 1499 } finally { 1500 // detect other types of Throwable and cancel this Timer 1501 if (!success) { 1502 cancel(); 1503 } 1504 } 1505 } 1506 1507 /** 1508 * {@inheritDoc} 1509 */ 1510 @Override 1511 public String toString() { 1512 final StringBuffer sb = new StringBuffer(); 1513 sb.append("KeyedObjectPoolMinIdleTimerTask"); 1514 sb.append("{minIdle=").append(minIdle); 1515 sb.append(", key=").append(key); 1516 sb.append(", keyedPool=").append(keyedPool); 1517 sb.append('}'); 1518 return sb.toString(); 1519 } 1520 } 1521 1522 /** 1523 * A synchronized (thread-safe) ObjectPool backed by the specified ObjectPool. 1524 * 1525 * <p><b>Note:</b> 1526 * This should not be used on pool implementations that already provide proper synchronization 1527 * such as the pools provided in the Commons Pool library. Wrapping a pool that 1528 * {@link #wait() waits} for poolable objects to be returned before allowing another one to be 1529 * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. 1530 * </p> 1531 */ 1532 private static class SynchronizedObjectPool<T> implements ObjectPool<T> { 1533 1534 /** Object whose monitor is used to synchronize methods on the wrapped pool. */ 1535 private final Object lock; 1536 1537 /** the underlying object pool */ 1538 private final ObjectPool<T> pool; 1539 1540 /** 1541 * Create a new SynchronizedObjectPool wrapping the given pool. 1542 * 1543 * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. 1544 * @throws IllegalArgumentException if the pool is null 1545 */ 1546 SynchronizedObjectPool(final ObjectPool<T> pool) throws IllegalArgumentException { 1547 if (pool == null) { 1548 throw new IllegalArgumentException("pool must not be null."); 1549 } 1550 this.pool = pool; 1551 lock = new Object(); 1552 } 1553 1554 /** 1555 * {@inheritDoc} 1556 */ 1557 public T borrowObject() throws Exception, NoSuchElementException, IllegalStateException { 1558 synchronized (lock) { 1559 return pool.borrowObject(); 1560 } 1561 } 1562 1563 /** 1564 * {@inheritDoc} 1565 */ 1566 public void returnObject(final T obj) { 1567 synchronized (lock) { 1568 try { 1569 pool.returnObject(obj); 1570 } catch (Exception e) { 1571 // swallowed as of Pool 2 1572 } 1573 } 1574 } 1575 1576 /** 1577 * {@inheritDoc} 1578 */ 1579 public void invalidateObject(final T obj) { 1580 synchronized (lock) { 1581 try { 1582 pool.invalidateObject(obj); 1583 } catch (Exception e) { 1584 // swallowed as of Pool 2 1585 } 1586 } 1587 } 1588 1589 /** 1590 * {@inheritDoc} 1591 */ 1592 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { 1593 synchronized (lock) { 1594 pool.addObject(); 1595 } 1596 } 1597 1598 /** 1599 * {@inheritDoc} 1600 */ 1601 public int getNumIdle() throws UnsupportedOperationException { 1602 synchronized (lock) { 1603 return pool.getNumIdle(); 1604 } 1605 } 1606 1607 /** 1608 * {@inheritDoc} 1609 */ 1610 public int getNumActive() throws UnsupportedOperationException { 1611 synchronized (lock) { 1612 return pool.getNumActive(); 1613 } 1614 } 1615 1616 /** 1617 * {@inheritDoc} 1618 */ 1619 public void clear() throws Exception, UnsupportedOperationException { 1620 synchronized (lock) { 1621 pool.clear(); 1622 } 1623 } 1624 1625 /** 1626 * {@inheritDoc} 1627 */ 1628 public void close() { 1629 try { 1630 synchronized (lock) { 1631 pool.close(); 1632 } 1633 } catch (Exception e) { 1634 // swallowed as of Pool 2 1635 } 1636 } 1637 1638 /** 1639 * Sets the factory used by the pool. 1640 * 1641 * @param factory new PoolableObjectFactory 1642 * @deprecated to be removed in pool 2.0 1643 */ 1644 @Deprecated 1645 public void setFactory(final PoolableObjectFactory<T> factory) throws IllegalStateException, UnsupportedOperationException { 1646 synchronized (lock) { 1647 pool.setFactory(factory); 1648 } 1649 } 1650 1651 /** 1652 * {@inheritDoc} 1653 */ 1654 @Override 1655 public String toString() { 1656 final StringBuffer sb = new StringBuffer(); 1657 sb.append("SynchronizedObjectPool"); 1658 sb.append("{pool=").append(pool); 1659 sb.append('}'); 1660 return sb.toString(); 1661 } 1662 } 1663 1664 /** 1665 * A synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. 1666 * 1667 * <p><b>Note:</b> 1668 * This should not be used on pool implementations that already provide proper synchronization 1669 * such as the pools provided in the Commons Pool library. Wrapping a pool that 1670 * {@link #wait() waits} for poolable objects to be returned before allowing another one to be 1671 * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. 1672 * </p> 1673 */ 1674 private static class SynchronizedKeyedObjectPool<K, V> implements KeyedObjectPool<K, V> { 1675 1676 /** Object whose monitor is used to synchronize methods on the wrapped pool. */ 1677 private final Object lock; 1678 1679 /** Underlying object pool */ 1680 private final KeyedObjectPool<K, V> keyedPool; 1681 1682 /** 1683 * Create a new SynchronizedKeyedObjectPool wrapping the given pool 1684 * 1685 * @param keyedPool KeyedObjectPool to wrap 1686 * @throws IllegalArgumentException if keyedPool is null 1687 */ 1688 SynchronizedKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool) throws IllegalArgumentException { 1689 if (keyedPool == null) { 1690 throw new IllegalArgumentException("keyedPool must not be null."); 1691 } 1692 this.keyedPool = keyedPool; 1693 lock = new Object(); 1694 } 1695 1696 /** 1697 * {@inheritDoc} 1698 */ 1699 public V borrowObject(final K key) throws Exception, NoSuchElementException, IllegalStateException { 1700 synchronized (lock) { 1701 return keyedPool.borrowObject(key); 1702 } 1703 } 1704 1705 /** 1706 * {@inheritDoc} 1707 */ 1708 public void returnObject(final K key, final V obj) { 1709 synchronized (lock) { 1710 try { 1711 keyedPool.returnObject(key, obj); 1712 } catch (Exception e) { 1713 // swallowed 1714 } 1715 } 1716 } 1717 1718 /** 1719 * {@inheritDoc} 1720 */ 1721 public void invalidateObject(final K key, final V obj) { 1722 synchronized (lock) { 1723 try { 1724 keyedPool.invalidateObject(key, obj); 1725 } catch (Exception e) { 1726 // swallowed as of Pool 2 1727 } 1728 } 1729 } 1730 1731 /** 1732 * {@inheritDoc} 1733 */ 1734 public void addObject(final K key) throws Exception, IllegalStateException, UnsupportedOperationException { 1735 synchronized (lock) { 1736 keyedPool.addObject(key); 1737 } 1738 } 1739 1740 /** 1741 * {@inheritDoc} 1742 */ 1743 public int getNumIdle(final K key) throws UnsupportedOperationException { 1744 synchronized (lock) { 1745 return keyedPool.getNumIdle(key); 1746 } 1747 } 1748 1749 /** 1750 * {@inheritDoc} 1751 */ 1752 public int getNumActive(final K key) throws UnsupportedOperationException { 1753 synchronized (lock) { 1754 return keyedPool.getNumActive(key); 1755 } 1756 } 1757 1758 /** 1759 * {@inheritDoc} 1760 */ 1761 public int getNumIdle() throws UnsupportedOperationException { 1762 synchronized (lock) { 1763 return keyedPool.getNumIdle(); 1764 } 1765 } 1766 1767 /** 1768 * {@inheritDoc} 1769 */ 1770 public int getNumActive() throws UnsupportedOperationException { 1771 synchronized (lock) { 1772 return keyedPool.getNumActive(); 1773 } 1774 } 1775 1776 /** 1777 * {@inheritDoc} 1778 */ 1779 public void clear() throws Exception, UnsupportedOperationException { 1780 synchronized (lock) { 1781 keyedPool.clear(); 1782 } 1783 } 1784 1785 /** 1786 * {@inheritDoc} 1787 */ 1788 public void clear(final K key) throws Exception, UnsupportedOperationException { 1789 synchronized (lock) { 1790 keyedPool.clear(key); 1791 } 1792 } 1793 1794 /** 1795 * {@inheritDoc} 1796 */ 1797 public void close() { 1798 try { 1799 synchronized (lock) { 1800 keyedPool.close(); 1801 } 1802 } catch (Exception e) { 1803 // swallowed as of Pool 2 1804 } 1805 } 1806 1807 /** 1808 * Sets the object factory used by the pool. 1809 * 1810 * @param factory KeyedPoolableObjectFactory used by the pool 1811 * @deprecated to be removed in pool 2.0 1812 */ 1813 @Deprecated 1814 public void setFactory(final KeyedPoolableObjectFactory<K, V> factory) throws IllegalStateException, UnsupportedOperationException { 1815 synchronized (lock) { 1816 keyedPool.setFactory(factory); 1817 } 1818 } 1819 1820 /** 1821 * {@inheritDoc} 1822 */ 1823 @Override 1824 public String toString() { 1825 final StringBuffer sb = new StringBuffer(); 1826 sb.append("SynchronizedKeyedObjectPool"); 1827 sb.append("{keyedPool=").append(keyedPool); 1828 sb.append('}'); 1829 return sb.toString(); 1830 } 1831 } 1832 1833 /** 1834 * A fully synchronized PoolableObjectFactory that wraps a PoolableObjectFactory and synchronizes 1835 * access to the wrapped factory methods. 1836 * 1837 * <p><b>Note:</b> 1838 * This should not be used on pool implementations that already provide proper synchronization 1839 * such as the pools provided in the Commons Pool library. </p> 1840 */ 1841 private static class SynchronizedPoolableObjectFactory<T> implements PoolableObjectFactory<T> { 1842 /** Synchronization lock */ 1843 private final Object lock; 1844 1845 /** Wrapped factory */ 1846 private final PoolableObjectFactory<T> factory; 1847 1848 /** 1849 * Create a SynchronizedPoolableObjectFactory wrapping the given factory. 1850 * 1851 * @param factory underlying factory to wrap 1852 * @throws IllegalArgumentException if the factory is null 1853 */ 1854 SynchronizedPoolableObjectFactory(final PoolableObjectFactory<T> factory) throws IllegalArgumentException { 1855 if (factory == null) { 1856 throw new IllegalArgumentException("factory must not be null."); 1857 } 1858 this.factory = factory; 1859 lock = new Object(); 1860 } 1861 1862 /** 1863 * {@inheritDoc} 1864 */ 1865 public T makeObject() throws Exception { 1866 synchronized (lock) { 1867 return factory.makeObject(); 1868 } 1869 } 1870 1871 /** 1872 * {@inheritDoc} 1873 */ 1874 public void destroyObject(final T obj) throws Exception { 1875 synchronized (lock) { 1876 factory.destroyObject(obj); 1877 } 1878 } 1879 1880 /** 1881 * {@inheritDoc} 1882 */ 1883 public boolean validateObject(final T obj) { 1884 synchronized (lock) { 1885 return factory.validateObject(obj); 1886 } 1887 } 1888 1889 /** 1890 * {@inheritDoc} 1891 */ 1892 public void activateObject(final T obj) throws Exception { 1893 synchronized (lock) { 1894 factory.activateObject(obj); 1895 } 1896 } 1897 1898 /** 1899 * {@inheritDoc} 1900 */ 1901 public void passivateObject(final T obj) throws Exception { 1902 synchronized (lock) { 1903 factory.passivateObject(obj); 1904 } 1905 } 1906 1907 /** 1908 * {@inheritDoc} 1909 */ 1910 @Override 1911 public String toString() { 1912 final StringBuffer sb = new StringBuffer(); 1913 sb.append("SynchronizedPoolableObjectFactory"); 1914 sb.append("{factory=").append(factory); 1915 sb.append('}'); 1916 return sb.toString(); 1917 } 1918 } 1919 1920 /** 1921 * A fully synchronized KeyedPoolableObjectFactory that wraps a KeyedPoolableObjectFactory and synchronizes 1922 * access to the wrapped factory methods. 1923 * 1924 * <p><b>Note:</b> 1925 * This should not be used on pool implementations that already provide proper synchronization 1926 * such as the pools provided in the Commons Pool library. </p> 1927 */ 1928 private static class SynchronizedKeyedPoolableObjectFactory<K, V> implements KeyedPoolableObjectFactory<K, V> { 1929 /** Synchronization lock */ 1930 private final Object lock; 1931 1932 /** Wrapped factory */ 1933 private final KeyedPoolableObjectFactory<K, V> keyedFactory; 1934 1935 /** 1936 * Create a SynchronizedKeyedPoolableObjectFactory wrapping the given factory. 1937 * 1938 * @param keyedFactory underlying factory to wrap 1939 * @throws IllegalArgumentException if the factory is null 1940 */ 1941 SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory<K, V> keyedFactory) throws IllegalArgumentException { 1942 if (keyedFactory == null) { 1943 throw new IllegalArgumentException("keyedFactory must not be null."); 1944 } 1945 this.keyedFactory = keyedFactory; 1946 lock = new Object(); 1947 } 1948 1949 /** 1950 * {@inheritDoc} 1951 */ 1952 public V makeObject(final K key) throws Exception { 1953 synchronized (lock) { 1954 return keyedFactory.makeObject(key); 1955 } 1956 } 1957 1958 /** 1959 * {@inheritDoc} 1960 */ 1961 public void destroyObject(final K key, final V obj) throws Exception { 1962 synchronized (lock) { 1963 keyedFactory.destroyObject(key, obj); 1964 } 1965 } 1966 1967 /** 1968 * {@inheritDoc} 1969 */ 1970 public boolean validateObject(final K key, final V obj) { 1971 synchronized (lock) { 1972 return keyedFactory.validateObject(key, obj); 1973 } 1974 } 1975 1976 /** 1977 * {@inheritDoc} 1978 */ 1979 public void activateObject(final K key, final V obj) throws Exception { 1980 synchronized (lock) { 1981 keyedFactory.activateObject(key, obj); 1982 } 1983 } 1984 1985 /** 1986 * {@inheritDoc} 1987 */ 1988 public void passivateObject(final K key, final V obj) throws Exception { 1989 synchronized (lock) { 1990 keyedFactory.passivateObject(key, obj); 1991 } 1992 } 1993 1994 /** 1995 * {@inheritDoc} 1996 */ 1997 @Override 1998 public String toString() { 1999 final StringBuffer sb = new StringBuffer(); 2000 sb.append("SynchronizedKeyedPoolableObjectFactory"); 2001 sb.append("{keyedFactory=").append(keyedFactory); 2002 sb.append('}'); 2003 return sb.toString(); 2004 } 2005 } 2006 2007 /** 2008 * Encapsulate the logic for when the next poolable object should be discarded. 2009 * Each time update is called, the next time to shrink is recomputed, based on 2010 * the float factor, number of idle instances in the pool and high water mark. 2011 * Float factor is assumed to be between 0 and 1. Values closer to 1 cause 2012 * less frequent erosion events. Erosion event timing also depends on numIdle. 2013 * When this value is relatively high (close to previously established high water 2014 * mark), erosion occurs more frequently. 2015 */ 2016 private static class ErodingFactor { 2017 /** Determines frequency of "erosion" events */ 2018 private final float factor; 2019 2020 /** Time of next shrink event */ 2021 private transient volatile long nextShrink; 2022 2023 /** High water mark - largest numIdle encountered */ 2024 private transient volatile int idleHighWaterMark; 2025 2026 /** 2027 * Create a new ErodingFactor with the given erosion factor. 2028 * 2029 * @param factor erosion factor 2030 */ 2031 public ErodingFactor(final float factor) { 2032 this.factor = factor; 2033 nextShrink = System.currentTimeMillis() + (long)(900000 * factor); // now + 15 min * factor 2034 idleHighWaterMark = 1; 2035 } 2036 2037 /** 2038 * Updates internal state based on numIdle and the current time. 2039 * 2040 * @param numIdle number of idle elements in the pool 2041 */ 2042 public void update(final int numIdle) { 2043 update(System.currentTimeMillis(), numIdle); 2044 } 2045 2046 /** 2047 * Updates internal state using the supplied time and numIdle. 2048 * 2049 * @param now current time 2050 * @param numIdle number of idle elements in the pool 2051 */ 2052 public void update(final long now, final int numIdle) { 2053 final int idle = Math.max(0, numIdle); 2054 idleHighWaterMark = Math.max(idle, idleHighWaterMark); 2055 final float maxInterval = 15f; 2056 final float minutes = maxInterval + ((1f-maxInterval)/idleHighWaterMark) * idle; 2057 nextShrink = now + (long)(minutes * 60000f * factor); 2058 } 2059 2060 /** 2061 * Returns the time of the next erosion event. 2062 * 2063 * @return next shrink time 2064 */ 2065 public long getNextShrink() { 2066 return nextShrink; 2067 } 2068 2069 /** 2070 * {@inheritDoc} 2071 */ 2072 @Override 2073 public String toString() { 2074 return "ErodingFactor{" + 2075 "factor=" + factor + 2076 ", idleHighWaterMark=" + idleHighWaterMark + 2077 '}'; 2078 } 2079 } 2080 2081 /** 2082 * Decorates an object pool, adding "eroding" behavior. Based on the 2083 * configured {@link #factor erosion factor}, objects returning to the pool 2084 * may be invalidated instead of being added to idle capacity. 2085 * 2086 */ 2087 private static class ErodingObjectPool<T> implements ObjectPool<T> { 2088 /** Underlying object pool */ 2089 private final ObjectPool<T> pool; 2090 2091 /** Erosion factor */ 2092 private final ErodingFactor factor; 2093 2094 /** 2095 * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. 2096 * 2097 * @param pool underlying pool 2098 * @param factor erosion factor - determines the frequency of erosion events 2099 * @see #factor 2100 */ 2101 public ErodingObjectPool(final ObjectPool<T> pool, final float factor) { 2102 this.pool = pool; 2103 this.factor = new ErodingFactor(factor); 2104 } 2105 2106 /** 2107 * {@inheritDoc} 2108 */ 2109 public T borrowObject() throws Exception, NoSuchElementException, IllegalStateException { 2110 return pool.borrowObject(); 2111 } 2112 2113 /** 2114 * Returns obj to the pool, unless erosion is triggered, in which 2115 * case obj is invalidated. Erosion is triggered when there are idle instances in 2116 * the pool and more than the {@link #factor erosion factor}-determined time has elapsed 2117 * since the last returnObject activation. 2118 * 2119 * @param obj object to return or invalidate 2120 * @see #factor 2121 */ 2122 public void returnObject(final T obj) { 2123 boolean discard = false; 2124 final long now = System.currentTimeMillis(); 2125 synchronized (pool) { 2126 if (factor.getNextShrink() < now) { // XXX: Pool 3: move test out of sync block 2127 final int numIdle = pool.getNumIdle(); 2128 if (numIdle > 0) { 2129 discard = true; 2130 } 2131 2132 factor.update(now, numIdle); 2133 } 2134 } 2135 try { 2136 if (discard) { 2137 pool.invalidateObject(obj); 2138 } else { 2139 pool.returnObject(obj); 2140 } 2141 } catch (Exception e) { 2142 // swallowed 2143 } 2144 } 2145 2146 /** 2147 * {@inheritDoc} 2148 */ 2149 public void invalidateObject(final T obj) { 2150 try { 2151 pool.invalidateObject(obj); 2152 } catch (Exception e) { 2153 // swallowed 2154 } 2155 } 2156 2157 /** 2158 * {@inheritDoc} 2159 */ 2160 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { 2161 pool.addObject(); 2162 } 2163 2164 /** 2165 * {@inheritDoc} 2166 */ 2167 public int getNumIdle() throws UnsupportedOperationException { 2168 return pool.getNumIdle(); 2169 } 2170 2171 /** 2172 * {@inheritDoc} 2173 */ 2174 public int getNumActive() throws UnsupportedOperationException { 2175 return pool.getNumActive(); 2176 } 2177 2178 /** 2179 * {@inheritDoc} 2180 */ 2181 public void clear() throws Exception, UnsupportedOperationException { 2182 pool.clear(); 2183 } 2184 2185 /** 2186 * {@inheritDoc} 2187 */ 2188 public void close() { 2189 try { 2190 pool.close(); 2191 } catch (Exception e) { 2192 // swallowed 2193 } 2194 } 2195 2196 /** 2197 * {@inheritDoc} 2198 * @deprecated to be removed in pool 2.0 2199 */ 2200 @Deprecated 2201 public void setFactory(final PoolableObjectFactory<T> factory) throws IllegalStateException, UnsupportedOperationException { 2202 pool.setFactory(factory); 2203 } 2204 2205 /** 2206 * {@inheritDoc} 2207 */ 2208 @Override 2209 public String toString() { 2210 return "ErodingObjectPool{" + 2211 "factor=" + factor + 2212 ", pool=" + pool + 2213 '}'; 2214 } 2215 } 2216 2217 /** 2218 * Decorates a keyed object pool, adding "eroding" behavior. Based on the 2219 * configured {@link #factor erosion factor}, objects returning to the pool 2220 * may be invalidated instead of being added to idle capacity. 2221 * 2222 */ 2223 private static class ErodingKeyedObjectPool<K, V> implements KeyedObjectPool<K, V> { 2224 /** Underlying pool */ 2225 private final KeyedObjectPool<K, V> keyedPool; 2226 2227 /** Erosion factor */ 2228 private final ErodingFactor erodingFactor; 2229 2230 /** 2231 * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. 2232 * 2233 * @param keyedPool underlying pool 2234 * @param factor erosion factor - determines the frequency of erosion events 2235 * @see #erodingFactor 2236 */ 2237 public ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final float factor) { 2238 this(keyedPool, new ErodingFactor(factor)); 2239 } 2240 2241 /** 2242 * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. 2243 * 2244 * @param keyedPool underlying pool - must not be null 2245 * @param erodingFactor erosion factor - determines the frequency of erosion events 2246 * @see #factor 2247 */ 2248 protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final ErodingFactor erodingFactor) { 2249 if (keyedPool == null) { 2250 throw new IllegalArgumentException("keyedPool must not be null."); 2251 } 2252 this.keyedPool = keyedPool; 2253 this.erodingFactor = erodingFactor; 2254 } 2255 2256 /** 2257 * {@inheritDoc} 2258 */ 2259 public V borrowObject(final K key) throws Exception, NoSuchElementException, IllegalStateException { 2260 return keyedPool.borrowObject(key); 2261 } 2262 2263 /** 2264 * Returns obj to the pool, unless erosion is triggered, in which 2265 * case obj is invalidated. Erosion is triggered when there are idle instances in 2266 * the pool associated with the given key and more than the configured {@link #erodingFactor erosion factor} 2267 * time has elapsed since the last returnObject activation. 2268 * 2269 * @param obj object to return or invalidate 2270 * @param key key 2271 * @see #erodingFactor 2272 */ 2273 public void returnObject(final K key, final V obj) throws Exception { 2274 boolean discard = false; 2275 final long now = System.currentTimeMillis(); 2276 final ErodingFactor factor = getErodingFactor(key); 2277 synchronized (keyedPool) { 2278 if (factor.getNextShrink() < now) { 2279 final int numIdle = numIdle(key); 2280 if (numIdle > 0) { 2281 discard = true; 2282 } 2283 2284 factor.update(now, numIdle); 2285 } 2286 } 2287 try { 2288 if (discard) { 2289 keyedPool.invalidateObject(key, obj); 2290 } else { 2291 keyedPool.returnObject(key, obj); 2292 } 2293 } catch (Exception e) { 2294 // swallowed 2295 } 2296 } 2297 2298 /** 2299 * Returns the total number of instances currently idle in this pool (optional operation). 2300 * Returns a negative value if this information is not available. 2301 * 2302 * @param key ignored 2303 * @return the total number of instances currently idle in this pool or a negative value if unsupported 2304 * @throws UnsupportedOperationException <strong>deprecated</strong>: when this implementation doesn't support the operation 2305 */ 2306 protected int numIdle(final K key) { 2307 return getKeyedPool().getNumIdle(); 2308 } 2309 2310 /** 2311 * Returns the eroding factor for the given key 2312 * @param key key 2313 * @return eroding factor for the given keyed pool 2314 */ 2315 protected ErodingFactor getErodingFactor(final K key) { 2316 return erodingFactor; 2317 } 2318 2319 /** 2320 * {@inheritDoc} 2321 */ 2322 public void invalidateObject(final K key, final V obj) { 2323 try { 2324 keyedPool.invalidateObject(key, obj); 2325 } catch (Exception e) { 2326 // swallowed 2327 } 2328 } 2329 2330 /** 2331 * {@inheritDoc} 2332 */ 2333 public void addObject(final K key) throws Exception, IllegalStateException, UnsupportedOperationException { 2334 keyedPool.addObject(key); 2335 } 2336 2337 /** 2338 * {@inheritDoc} 2339 */ 2340 public int getNumIdle() throws UnsupportedOperationException { 2341 return keyedPool.getNumIdle(); 2342 } 2343 2344 /** 2345 * {@inheritDoc} 2346 */ 2347 public int getNumIdle(final K key) throws UnsupportedOperationException { 2348 return keyedPool.getNumIdle(key); 2349 } 2350 2351 /** 2352 * {@inheritDoc} 2353 */ 2354 public int getNumActive() throws UnsupportedOperationException { 2355 return keyedPool.getNumActive(); 2356 } 2357 2358 /** 2359 * {@inheritDoc} 2360 */ 2361 public int getNumActive(final K key) throws UnsupportedOperationException { 2362 return keyedPool.getNumActive(key); 2363 } 2364 2365 /** 2366 * {@inheritDoc} 2367 */ 2368 public void clear() throws Exception, UnsupportedOperationException { 2369 keyedPool.clear(); 2370 } 2371 2372 /** 2373 * {@inheritDoc} 2374 */ 2375 public void clear(final K key) throws Exception, UnsupportedOperationException { 2376 keyedPool.clear(key); 2377 } 2378 2379 /** 2380 * {@inheritDoc} 2381 */ 2382 public void close() { 2383 try { 2384 keyedPool.close(); 2385 } catch (Exception e) { 2386 // swallowed 2387 } 2388 } 2389 2390 /** 2391 * {@inheritDoc} 2392 * @deprecated to be removed in pool 2.0 2393 */ 2394 @Deprecated 2395 public void setFactory(final KeyedPoolableObjectFactory<K, V> factory) throws IllegalStateException, UnsupportedOperationException { 2396 keyedPool.setFactory(factory); 2397 } 2398 2399 /** 2400 * Returns the underlying pool 2401 * 2402 * @return the keyed pool that this ErodingKeyedObjectPool wraps 2403 */ 2404 protected KeyedObjectPool<K, V> getKeyedPool() { 2405 return keyedPool; 2406 } 2407 2408 /** 2409 * {@inheritDoc} 2410 */ 2411 @Override 2412 public String toString() { 2413 return "ErodingKeyedObjectPool{" + 2414 "erodingFactor=" + erodingFactor + 2415 ", keyedPool=" + keyedPool + 2416 '}'; 2417 } 2418 } 2419 2420 /** 2421 * Extends ErodingKeyedObjectPool to allow erosion to take place on a per-key 2422 * basis. Timing of erosion events is tracked separately for separate keyed pools. 2423 */ 2424 private static class ErodingPerKeyKeyedObjectPool<K, V> extends ErodingKeyedObjectPool<K, V> { 2425 /** Erosion factor - same for all pools */ 2426 private final float factor; 2427 2428 /** Map of ErodingFactor instances keyed on pool keys */ 2429 private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<K, ErodingFactor>()); 2430 2431 /** 2432 * Create a new ErordingPerKeyKeyedObjectPool decorating the given keyed pool with 2433 * the specified erosion factor. 2434 * @param keyedPool underlying keyed pool 2435 * @param factor erosion factor 2436 */ 2437 public ErodingPerKeyKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool, final float factor) { 2438 super(keyedPool, null); 2439 this.factor = factor; 2440 } 2441 2442 /** 2443 * {@inheritDoc} 2444 */ 2445 @Override 2446 protected int numIdle(final K key) { 2447 return getKeyedPool().getNumIdle(key); 2448 } 2449 2450 /** 2451 * {@inheritDoc} 2452 */ 2453 @Override 2454 protected ErodingFactor getErodingFactor(final K key) { 2455 ErodingFactor factor = factors.get(key); 2456 // this may result in two ErodingFactors being created for a key 2457 // since they are small and cheap this is okay. 2458 if (factor == null) { 2459 factor = new ErodingFactor(this.factor); 2460 factors.put(key, factor); 2461 } 2462 return factor; 2463 } 2464 2465 /** 2466 * {@inheritDoc} 2467 */ 2468 @Override 2469 public String toString() { 2470 return "ErodingPerKeyKeyedObjectPool{" + 2471 "factor=" + factor + 2472 ", keyedPool=" + getKeyedPool() + 2473 '}'; 2474 } 2475 } 2476 }