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 }