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