1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.pool;
19
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.NoSuchElementException;
25 import java.util.Timer;
26 import java.util.TimerTask;
27 import java.util.Collections;
28
29 /***
30 * This class consists exclusively of static methods that operate on or return ObjectPool
31 * or KeyedObjectPool related interfaces.
32 *
33 * @author Sandy McArthur
34 * @version $Revision: 607796 $ $Date: 2007-12-31 20:35:49 -0700 (Mon, 31 Dec 2007) $
35 * @since Pool 1.3
36 */
37 public final class PoolUtils {
38
39 /***
40 * Timer used to periodically check pools idle object count.
41 * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated.
42 */
43 private static Timer MIN_IDLE_TIMER;
44
45 /***
46 * PoolUtils instances should NOT be constructed in standard programming.
47 * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
48 * This constructor is public to permit tools that require a JavaBean instance to operate.
49 */
50 public PoolUtils() {
51 }
52
53 /***
54 * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
55 * needed. This method is the equivalent of calling
56 * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}.
57 *
58 * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
59 * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key.
60 * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>.
61 * @see #adapt(KeyedPoolableObjectFactory, Object)
62 * @since Pool 1.3
63 */
64 public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
65 return adapt(keyedFactory, new Object());
66 }
67
68 /***
69 * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
70 * needed using the specified <code>key</code> when delegating.
71 *
72 * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
73 * @param key the key to use when delegating.
74 * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key.
75 * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>.
76 * @see #adapt(KeyedPoolableObjectFactory)
77 * @since Pool 1.3
78 */
79 public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException {
80 return new PoolableObjectFactoryAdaptor(keyedFactory, key);
81 }
82
83 /***
84 * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is
85 * needed. The key is ignored.
86 *
87 * @param factory the {@link PoolableObjectFactory} to delegate to.
88 * @return a {@link KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key.
89 * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>.
90 * @since Pool 1.3
91 */
92 public static KeyedPoolableObjectFactory adapt(final PoolableObjectFactory factory) throws IllegalArgumentException {
93 return new KeyedPoolableObjectFactoryAdaptor(factory);
94 }
95
96 /***
97 * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the
98 * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}.
99 *
100 * @param keyedPool the {@link KeyedObjectPool} to delegate to.
101 * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with an internal key.
102 * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>.
103 * @see #adapt(KeyedObjectPool, Object)
104 * @since Pool 1.3
105 */
106 public static ObjectPool adapt(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
107 return adapt(keyedPool, new Object());
108 }
109
110 /***
111 * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the
112 * specified <code>key</code> when delegating.
113 *
114 * @param keyedPool the {@link KeyedObjectPool} to delegate to.
115 * @param key the key to use when delegating.
116 * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with the specified key.
117 * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
118 * @see #adapt(KeyedObjectPool)
119 * @since Pool 1.3
120 */
121 public static ObjectPool adapt(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
122 return new ObjectPoolAdaptor(keyedPool, key);
123 }
124
125 /***
126 * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed.
127 * The key is ignored.
128 *
129 * @param pool the {@link ObjectPool} to delegate to.
130 * @return a {@link KeyedObjectPool} that delegates to <code>pool</code> ignoring the key.
131 * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>.
132 * @since Pool 1.3
133 */
134 public static KeyedObjectPool adapt(final ObjectPool pool) throws IllegalArgumentException {
135 return new KeyedObjectPoolAdaptor(pool);
136 }
137
138 /***
139 * Wraps an <code>ObjectPool</code> and dynamically checks the type of objects borrowed and returned to the pool.
140 * If an object is passed to the pool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
141 *
142 * @param pool the pool to enforce type safety on
143 * @param type the class type to enforce.
144 * @return an <code>ObjectPool</code> that will only allow objects of <code>type</code>
145 * @since Pool 1.3
146 */
147 public static ObjectPool checkedPool(final ObjectPool pool, final Class type) {
148 if (pool == null) {
149 throw new IllegalArgumentException("pool must not be null.");
150 }
151 if (type == null) {
152 throw new IllegalArgumentException("type must not be null.");
153 }
154 return new CheckedObjectPool(pool, type);
155 }
156
157 /***
158 * Wraps a <code>KeyedObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool.
159 * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
160 *
161 * @param keyedPool the keyedPool to enforce type safety on
162 * @param type the class type to enforce.
163 * @return a <code>KeyedObjectPool</code> that will only allow objects of <code>type</code>
164 * @since Pool 1.3
165 */
166 public static KeyedObjectPool checkedPool(final KeyedObjectPool keyedPool, final Class type) {
167 if (keyedPool == null) {
168 throw new IllegalArgumentException("keyedPool must not be null.");
169 }
170 if (type == null) {
171 throw new IllegalArgumentException("type must not be null.");
172 }
173 return new CheckedKeyedObjectPool(keyedPool, type);
174 }
175
176 /***
177 * Periodically check the idle object count for the pool. At most one idle object will be added per period.
178 * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed.
179 *
180 * @param pool the pool to check periodically.
181 * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object.
182 * @param period the frequency to check the number of idle objects in a pool, see
183 * {@link Timer#schedule(TimerTask, long, long)}.
184 * @return the {@link TimerTask} that will periodically check the pools idle object count.
185 * @throws IllegalArgumentException when <code>pool</code> is <code>null</code> or
186 * when <code>minIdle</code> is negative or when <code>period</code> isn't
187 * valid for {@link Timer#schedule(TimerTask, long, long)}.
188 * @since Pool 1.3
189 */
190 public static TimerTask checkMinIdle(final ObjectPool pool, final int minIdle, final long period) throws IllegalArgumentException {
191 if (pool == null) {
192 throw new IllegalArgumentException("keyedPool must not be null.");
193 }
194 if (minIdle < 0) {
195 throw new IllegalArgumentException("minIdle must be non-negative.");
196 }
197 final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle);
198 getMinIdleTimer().schedule(task, 0L, period);
199 return task;
200 }
201
202 /***
203 * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period.
204 * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key
205 * will be performed.
206 *
207 * @param keyedPool the keyedPool to check periodically.
208 * @param key the key to check the idle count of.
209 * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
210 * @param period the frequency to check the number of idle objects in a keyedPool, see
211 * {@link Timer#schedule(TimerTask, long, long)}.
212 * @return the {@link TimerTask} that will periodically check the pools idle object count.
213 * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or
214 * when <code>minIdle</code> is negative or when <code>period</code> isn't
215 * valid for {@link Timer#schedule(TimerTask, long, long)}.
216 * @since Pool 1.3
217 */
218 public static TimerTask checkMinIdle(final KeyedObjectPool keyedPool, final Object key, final int minIdle, final long period) throws IllegalArgumentException {
219 if (keyedPool == null) {
220 throw new IllegalArgumentException("keyedPool must not be null.");
221 }
222 if (key == null) {
223 throw new IllegalArgumentException("key must not be null.");
224 }
225 if (minIdle < 0) {
226 throw new IllegalArgumentException("minIdle must be non-negative.");
227 }
228 final TimerTask task = new KeyedObjectPoolMinIdleTimerTask(keyedPool, key, minIdle);
229 getMinIdleTimer().schedule(task, 0L, period);
230 return task;
231 }
232
233 /***
234 * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the keyedPool.
235 * At most one idle object will be added per period.
236 *
237 * @param keyedPool the keyedPool to check periodically.
238 * @param keys a collection of keys to check the idle object count.
239 * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
240 * @param period the frequency to check the number of idle objects in a keyedPool, see
241 * {@link Timer#schedule(TimerTask, long, long)}.
242 * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count.
243 * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the
244 * collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't
245 * valid for {@link Timer#schedule(TimerTask, long, long)}.
246 * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
247 * @since Pool 1.3
248 */
249 public static Map checkMinIdle(final KeyedObjectPool keyedPool, final Collection keys, final int minIdle, final long period) throws IllegalArgumentException {
250 if (keys == null) {
251 throw new IllegalArgumentException("keys must not be null.");
252 }
253 final Map tasks = new HashMap(keys.size());
254 final Iterator iter = keys.iterator();
255 while (iter.hasNext()) {
256 final Object key = iter.next();
257 final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
258 tasks.put(key, task);
259 }
260 return tasks;
261 }
262
263 /***
264 * Call <code>addObject()</code> on <code>pool</code> <code>count</code> number of times.
265 *
266 * @param pool the pool to prefill.
267 * @param count the number of idle objects to add.
268 * @throws Exception when {@link ObjectPool#addObject()} fails.
269 * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>.
270 * @since Pool 1.3
271 */
272 public static void prefill(final ObjectPool pool, final int count) throws Exception, IllegalArgumentException {
273 if (pool == null) {
274 throw new IllegalArgumentException("pool must not be null.");
275 }
276 for (int i = 0; i < count; i++) {
277 pool.addObject();
278 }
279 }
280
281 /***
282 * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code>
283 * number of times.
284 *
285 * @param keyedPool the keyedPool to prefill.
286 * @param key the key to add objects for.
287 * @param count the number of idle objects to add for <code>key</code>.
288 * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
289 * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
290 * @since Pool 1.3
291 */
292 public static void prefill(final KeyedObjectPool keyedPool, final Object key, final int count) throws Exception, IllegalArgumentException {
293 if (keyedPool == null) {
294 throw new IllegalArgumentException("keyedPool must not be null.");
295 }
296 if (key == null) {
297 throw new IllegalArgumentException("key must not be null.");
298 }
299 for (int i = 0; i < count; i++) {
300 keyedPool.addObject(key);
301 }
302 }
303
304 /***
305 * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for
306 * <code>count</code> number of times. This has the same effect as calling
307 * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection.
308 *
309 * @param keyedPool the keyedPool to prefill.
310 * @param keys {@link Collection} of keys to add objects for.
311 * @param count the number of idle objects to add for each <code>key</code>.
312 * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
313 * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or
314 * any value in <code>keys</code> is <code>null</code>.
315 * @see #prefill(KeyedObjectPool, Object, int)
316 * @since Pool 1.3
317 */
318 public static void prefill(final KeyedObjectPool keyedPool, final Collection keys, final int count) throws Exception, IllegalArgumentException {
319 if (keys == null) {
320 throw new IllegalArgumentException("keys must not be null.");
321 }
322 final Iterator iter = keys.iterator();
323 while (iter.hasNext()) {
324 prefill(keyedPool, iter.next(), count);
325 }
326 }
327
328 /***
329 * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool.
330 *
331 * <p><b>Note:</b>
332 * This should not be used on pool implementations that already provide proper synchronization
333 * such as the pools provided in the Commons Pool library. Wrapping a pool that
334 * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
335 * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
336 * </p>
337 *
338 * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool.
339 * @return a synchronized view of the specified ObjectPool.
340 * @since Pool 1.3
341 */
342 public static ObjectPool synchronizedPool(final ObjectPool pool) {
343 if (pool == null) {
344 throw new IllegalArgumentException("pool must not be null.");
345 }
346
347
348
349
350
351
352
353
354
355
356 return new SynchronizedObjectPool(pool);
357 }
358
359 /***
360 * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool.
361 *
362 * <p><b>Note:</b>
363 * This should not be used on pool implementations that already provide proper synchronization
364 * such as the pools provided in the Commons Pool library. Wrapping a pool that
365 * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
366 * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
367 * </p>
368 *
369 * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool.
370 * @return a synchronized view of the specified KeyedObjectPool.
371 * @since Pool 1.3
372 */
373 public static KeyedObjectPool synchronizedPool(final KeyedObjectPool keyedPool) {
374 if (keyedPool == null) {
375 throw new IllegalArgumentException("keyedPool must not be null.");
376 }
377
378
379
380
381
382
383
384
385 return new SynchronizedKeyedObjectPool(keyedPool);
386 }
387
388 /***
389 * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory.
390 *
391 * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory.
392 * @return a synchronized view of the specified PoolableObjectFactory.
393 * @since Pool 1.3
394 */
395 public static PoolableObjectFactory synchronizedPoolableFactory(final PoolableObjectFactory factory) {
396 return new SynchronizedPoolableObjectFactory(factory);
397 }
398
399 /***
400 * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory.
401 *
402 * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory.
403 * @return a synchronized view of the specified KeyedPoolableObjectFactory.
404 * @since Pool 1.3
405 */
406 public static KeyedPoolableObjectFactory synchronizedPoolableFactory(final KeyedPoolableObjectFactory keyedFactory) {
407 return new SynchronizedKeyedPoolableObjectFactory(keyedFactory);
408 }
409
410 /***
411 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
412 * This is intended as an always thread-safe alternative to using an idle object evictor
413 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
414 * pools that experience load spikes.
415 *
416 * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible.
417 * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
418 * @see #erodingPool(ObjectPool, float)
419 * @since Pool 1.4
420 */
421 public static ObjectPool erodingPool(final ObjectPool pool) {
422 return erodingPool(pool, 1f);
423 }
424
425 /***
426 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
427 * This is intended as an always thread-safe alternative to using an idle object evictor
428 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
429 * pools that experience load spikes.
430 *
431 * <p>
432 * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
433 * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
434 * Values greater than 1 cause the pool to less frequently try to shrink it's size.
435 * </p>
436 *
437 * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible.
438 * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
439 * If 0 < factor < 1 then the pool shrinks more aggressively.
440 * If 1 < factor then the pool shrinks less aggressively.
441 * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
442 * @see #erodingPool(ObjectPool)
443 * @since Pool 1.4
444 */
445 public static ObjectPool erodingPool(final ObjectPool pool, final float factor) {
446 if (pool == null) {
447 throw new IllegalArgumentException("pool must not be null.");
448 }
449 if (factor <= 0f) {
450 throw new IllegalArgumentException("factor must be positive.");
451 }
452 return new ErodingObjectPool(pool, factor);
453 }
454
455 /***
456 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
457 * This is intended as an always thread-safe alternative to using an idle object evictor
458 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
459 * pools that experience load spikes.
460 *
461 * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when
462 * possible.
463 * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
464 * @see #erodingPool(KeyedObjectPool, float)
465 * @see #erodingPool(KeyedObjectPool, float, boolean)
466 * @since Pool 1.4
467 */
468 public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool) {
469 return erodingPool(keyedPool, 1f);
470 }
471
472 /***
473 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
474 * This is intended as an always thread-safe alternative to using an idle object evictor
475 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
476 * pools that experience load spikes.
477 *
478 * <p>
479 * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
480 * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
481 * Values greater than 1 cause the pool to less frequently try to shrink it's size.
482 * </p>
483 *
484 * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when
485 * possible.
486 * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
487 * If 0 < factor < 1 then the pool shrinks more aggressively.
488 * If 1 < factor then the pool shrinks less aggressively.
489 * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
490 * @see #erodingPool(KeyedObjectPool, float, boolean)
491 * @since Pool 1.4
492 */
493 public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor) {
494 return erodingPool(keyedPool, factor, false);
495 }
496
497 /***
498 * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
499 * This is intended as an always thread-safe alternative to using an idle object evictor
500 * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
501 * pools that experience load spikes.
502 *
503 * <p>
504 * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
505 * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
506 * Values greater than 1 cause the pool to less frequently try to shrink it's size.
507 * </p>
508 *
509 * <p>
510 * The perKey parameter determines if the pool shrinks on a whole pool basis or a per key basis.
511 * When perKey is false, the keys do not have an effect on the rate at which the pool tries to
512 * shrink it's size. When perKey is true, each key is shrunk independently.
513 * </p>
514 *
515 * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when
516 * possible.
517 * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
518 * If 0 < factor < 1 then the pool shrinks more aggressively.
519 * If 1 < factor then the pool shrinks less aggressively.
520 * @param perKey when true, each key is treated independently.
521 * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
522 * @see #erodingPool(KeyedObjectPool)
523 * @see #erodingPool(KeyedObjectPool, float)
524 * @since Pool 1.4
525 */
526 public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor, final boolean perKey) {
527 if (keyedPool == null) {
528 throw new IllegalArgumentException("keyedPool must not be null.");
529 }
530 if (factor <= 0f) {
531 throw new IllegalArgumentException("factor must be positive.");
532 }
533 if (perKey) {
534 return new ErodingPerKeyKeyedObjectPool(keyedPool, factor);
535 } else {
536 return new ErodingKeyedObjectPool(keyedPool, factor);
537 }
538 }
539
540 /***
541 * Get the <code>Timer</code> for checking keyedPool's idle count. Lazily create the {@link Timer} as needed.
542 *
543 * @return the {@link Timer} for checking keyedPool's idle count.
544 * @since Pool 1.3
545 */
546 private static synchronized Timer getMinIdleTimer() {
547 if (MIN_IDLE_TIMER == null) {
548 MIN_IDLE_TIMER = new Timer(true);
549 }
550 return MIN_IDLE_TIMER;
551 }
552
553 private static class PoolableObjectFactoryAdaptor implements PoolableObjectFactory {
554 private final Object key;
555 private final KeyedPoolableObjectFactory keyedFactory;
556
557 PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException {
558 if (keyedFactory == null) {
559 throw new IllegalArgumentException("keyedFactory must not be null.");
560 }
561 if (key == null) {
562 throw new IllegalArgumentException("key must not be null.");
563 }
564 this.keyedFactory = keyedFactory;
565 this.key = key;
566 }
567
568 public Object makeObject() throws Exception {
569 return keyedFactory.makeObject(key);
570 }
571
572 public void destroyObject(final Object obj) throws Exception {
573 keyedFactory.destroyObject(key, obj);
574 }
575
576 public boolean validateObject(final Object obj) {
577 return keyedFactory.validateObject(key, obj);
578 }
579
580 public void activateObject(final Object obj) throws Exception {
581 keyedFactory.activateObject(key, obj);
582 }
583
584 public void passivateObject(final Object obj) throws Exception {
585 keyedFactory.passivateObject(key, obj);
586 }
587
588 public String toString() {
589 final StringBuffer sb = new StringBuffer();
590 sb.append("PoolableObjectFactoryAdaptor");
591 sb.append("{key=").append(key);
592 sb.append(", keyedFactory=").append(keyedFactory);
593 sb.append('}');
594 return sb.toString();
595 }
596 }
597
598 private static class KeyedPoolableObjectFactoryAdaptor implements KeyedPoolableObjectFactory {
599 private final PoolableObjectFactory factory;
600
601 KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory factory) throws IllegalArgumentException {
602 if (factory == null) {
603 throw new IllegalArgumentException("factory must not be null.");
604 }
605 this.factory = factory;
606 }
607
608 public Object makeObject(final Object key) throws Exception {
609 return factory.makeObject();
610 }
611
612 public void destroyObject(final Object key, final Object obj) throws Exception {
613 factory.destroyObject(obj);
614 }
615
616 public boolean validateObject(final Object key, final Object obj) {
617 return factory.validateObject(obj);
618 }
619
620 public void activateObject(final Object key, final Object obj) throws Exception {
621 factory.activateObject(obj);
622 }
623
624 public void passivateObject(final Object key, final Object obj) throws Exception {
625 factory.passivateObject(obj);
626 }
627
628 public String toString() {
629 final StringBuffer sb = new StringBuffer();
630 sb.append("KeyedPoolableObjectFactoryAdaptor");
631 sb.append("{factory=").append(factory);
632 sb.append('}');
633 return sb.toString();
634 }
635 }
636
637 private static class ObjectPoolAdaptor implements ObjectPool {
638 private final Object key;
639 private final KeyedObjectPool keyedPool;
640
641 ObjectPoolAdaptor(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
642 if (keyedPool == null) {
643 throw new IllegalArgumentException("keyedPool must not be null.");
644 }
645 if (key == null) {
646 throw new IllegalArgumentException("key must not be null.");
647 }
648 this.keyedPool = keyedPool;
649 this.key = key;
650 }
651
652 public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
653 return keyedPool.borrowObject(key);
654 }
655
656 public void returnObject(final Object obj) {
657 try {
658 keyedPool.returnObject(key, obj);
659 } catch (Exception e) {
660
661 }
662 }
663
664 public void invalidateObject(final Object obj) {
665 try {
666 keyedPool.invalidateObject(key, obj);
667 } catch (Exception e) {
668
669 }
670 }
671
672 public void addObject() throws Exception, IllegalStateException {
673 keyedPool.addObject(key);
674 }
675
676 public int getNumIdle() throws UnsupportedOperationException {
677 return keyedPool.getNumIdle(key);
678 }
679
680 public int getNumActive() throws UnsupportedOperationException {
681 return keyedPool.getNumActive(key);
682 }
683
684 public void clear() throws Exception, UnsupportedOperationException {
685 keyedPool.clear();
686 }
687
688 public void close() {
689 try {
690 keyedPool.close();
691 } catch (Exception e) {
692
693 }
694 }
695
696 public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
697 keyedPool.setFactory(adapt(factory));
698 }
699
700 public String toString() {
701 final StringBuffer sb = new StringBuffer();
702 sb.append("ObjectPoolAdaptor");
703 sb.append("{key=").append(key);
704 sb.append(", keyedPool=").append(keyedPool);
705 sb.append('}');
706 return sb.toString();
707 }
708 }
709
710 private static class KeyedObjectPoolAdaptor implements KeyedObjectPool {
711 private final ObjectPool pool;
712
713 KeyedObjectPoolAdaptor(final ObjectPool pool) throws IllegalArgumentException {
714 if (pool == null) {
715 throw new IllegalArgumentException("pool must not be null.");
716 }
717 this.pool = pool;
718 }
719
720 public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
721 return pool.borrowObject();
722 }
723
724 public void returnObject(final Object key, final Object obj) {
725 try {
726 pool.returnObject(obj);
727 } catch (Exception e) {
728
729 }
730 }
731
732 public void invalidateObject(final Object key, final Object obj) {
733 try {
734 pool.invalidateObject(obj);
735 } catch (Exception e) {
736
737 }
738 }
739
740 public void addObject(final Object key) throws Exception, IllegalStateException {
741 pool.addObject();
742 }
743
744 public int getNumIdle(final Object key) throws UnsupportedOperationException {
745 return pool.getNumIdle();
746 }
747
748 public int getNumActive(final Object key) throws UnsupportedOperationException {
749 return pool.getNumActive();
750 }
751
752 public int getNumIdle() throws UnsupportedOperationException {
753 return pool.getNumIdle();
754 }
755
756 public int getNumActive() throws UnsupportedOperationException {
757 return pool.getNumActive();
758 }
759
760 public void clear() throws Exception, UnsupportedOperationException {
761 pool.clear();
762 }
763
764 public void clear(final Object key) throws Exception, UnsupportedOperationException {
765 pool.clear();
766 }
767
768 public void close() {
769 try {
770 pool.close();
771 } catch (Exception e) {
772
773 }
774 }
775
776 public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
777 pool.setFactory(adapt(factory));
778 }
779
780 public String toString() {
781 final StringBuffer sb = new StringBuffer();
782 sb.append("KeyedObjectPoolAdaptor");
783 sb.append("{pool=").append(pool);
784 sb.append('}');
785 return sb.toString();
786 }
787 }
788
789 private static class CheckedObjectPool implements ObjectPool {
790 private final Class type;
791 private final ObjectPool pool;
792
793 CheckedObjectPool(final ObjectPool pool, final Class type) {
794 if (pool == null) {
795 throw new IllegalArgumentException("pool must not be null.");
796 }
797 if (type == null) {
798 throw new IllegalArgumentException("type must not be null.");
799 }
800 this.pool = pool;
801 this.type = type;
802 }
803
804 public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
805 final Object obj = pool.borrowObject();
806 if (type.isInstance(obj)) {
807 return obj;
808 } else {
809 throw new ClassCastException("Borrowed object is not of type: " + type.getName() + " was: " + obj);
810 }
811 }
812
813 public void returnObject(final Object obj) {
814 if (type.isInstance(obj)) {
815 try {
816 pool.returnObject(obj);
817 } catch (Exception e) {
818
819 }
820 } else {
821 throw new ClassCastException("Returned object is not of type: " + type.getName() + " was: " + obj);
822 }
823 }
824
825 public void invalidateObject(final Object obj) {
826 if (type.isInstance(obj)) {
827 try {
828 pool.invalidateObject(obj);
829 } catch (Exception e) {
830
831 }
832 } else {
833 throw new ClassCastException("Invalidated object is not of type: " + type.getName() + " was: " + obj);
834 }
835 }
836
837 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
838 pool.addObject();
839 }
840
841 public int getNumIdle() throws UnsupportedOperationException {
842 return pool.getNumIdle();
843 }
844
845 public int getNumActive() throws UnsupportedOperationException {
846 return pool.getNumActive();
847 }
848
849 public void clear() throws Exception, UnsupportedOperationException {
850 pool.clear();
851 }
852
853 public void close() {
854 try {
855 pool.close();
856 } catch (Exception e) {
857
858 }
859 }
860
861 public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
862 pool.setFactory(factory);
863 }
864
865 public String toString() {
866 final StringBuffer sb = new StringBuffer();
867 sb.append("CheckedObjectPool");
868 sb.append("{type=").append(type);
869 sb.append(", pool=").append(pool);
870 sb.append('}');
871 return sb.toString();
872 }
873 }
874
875 private static class CheckedKeyedObjectPool implements KeyedObjectPool {
876 private final Class type;
877 private final KeyedObjectPool keyedPool;
878
879 CheckedKeyedObjectPool(final KeyedObjectPool keyedPool, final Class type) {
880 if (keyedPool == null) {
881 throw new IllegalArgumentException("keyedPool must not be null.");
882 }
883 if (type == null) {
884 throw new IllegalArgumentException("type must not be null.");
885 }
886 this.keyedPool = keyedPool;
887 this.type = type;
888 }
889
890 public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
891 Object obj = keyedPool.borrowObject(key);
892 if (type.isInstance(obj)) {
893 return obj;
894 } else {
895 throw new ClassCastException("Borrowed object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
896 }
897 }
898
899 public void returnObject(final Object key, final Object obj) {
900 if (type.isInstance(obj)) {
901 try {
902 keyedPool.returnObject(key, obj);
903 } catch (Exception e) {
904
905 }
906 } else {
907 throw new ClassCastException("Returned object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
908 }
909 }
910
911 public void invalidateObject(final Object key, final Object obj) {
912 if (type.isInstance(obj)) {
913 try {
914 keyedPool.invalidateObject(key, obj);
915 } catch (Exception e) {
916
917 }
918 } else {
919 throw new ClassCastException("Invalidated object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
920 }
921 }
922
923 public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
924 keyedPool.addObject(key);
925 }
926
927 public int getNumIdle(final Object key) throws UnsupportedOperationException {
928 return keyedPool.getNumIdle(key);
929 }
930
931 public int getNumActive(final Object key) throws UnsupportedOperationException {
932 return keyedPool.getNumActive(key);
933 }
934
935 public int getNumIdle() throws UnsupportedOperationException {
936 return keyedPool.getNumIdle();
937 }
938
939 public int getNumActive() throws UnsupportedOperationException {
940 return keyedPool.getNumActive();
941 }
942
943 public void clear() throws Exception, UnsupportedOperationException {
944 keyedPool.clear();
945 }
946
947 public void clear(final Object key) throws Exception, UnsupportedOperationException {
948 keyedPool.clear(key);
949 }
950
951 public void close() {
952 try {
953 keyedPool.close();
954 } catch (Exception e) {
955
956 }
957 }
958
959 public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
960 keyedPool.setFactory(factory);
961 }
962
963 public String toString() {
964 final StringBuffer sb = new StringBuffer();
965 sb.append("CheckedKeyedObjectPool");
966 sb.append("{type=").append(type);
967 sb.append(", keyedPool=").append(keyedPool);
968 sb.append('}');
969 return sb.toString();
970 }
971 }
972
973 private static class ObjectPoolMinIdleTimerTask extends TimerTask {
974 private final int minIdle;
975 private final ObjectPool pool;
976
977 ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) throws IllegalArgumentException {
978 if (pool == null) {
979 throw new IllegalArgumentException("pool must not be null.");
980 }
981 this.pool = pool;
982 this.minIdle = minIdle;
983 }
984
985 public void run() {
986 boolean success = false;
987 try {
988 if (pool.getNumIdle() < minIdle) {
989 pool.addObject();
990 }
991 success = true;
992
993 } catch (Exception e) {
994 cancel();
995
996 } finally {
997
998 if (!success) {
999 cancel();
1000 }
1001 }
1002 }
1003
1004 public String toString() {
1005 final StringBuffer sb = new StringBuffer();
1006 sb.append("ObjectPoolMinIdleTimerTask");
1007 sb.append("{minIdle=").append(minIdle);
1008 sb.append(", pool=").append(pool);
1009 sb.append('}');
1010 return sb.toString();
1011 }
1012 }
1013
1014 private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask {
1015 private final int minIdle;
1016 private final Object key;
1017 private final KeyedObjectPool keyedPool;
1018
1019 KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, final Object key, final int minIdle) throws IllegalArgumentException {
1020 if (keyedPool == null) {
1021 throw new IllegalArgumentException("keyedPool must not be null.");
1022 }
1023 this.keyedPool = keyedPool;
1024 this.key = key;
1025 this.minIdle = minIdle;
1026 }
1027
1028 public void run() {
1029 boolean success = false;
1030 try {
1031 if (keyedPool.getNumIdle(key) < minIdle) {
1032 keyedPool.addObject(key);
1033 }
1034 success = true;
1035
1036 } catch (Exception e) {
1037 cancel();
1038
1039 } finally {
1040
1041 if (!success) {
1042 cancel();
1043 }
1044 }
1045 }
1046
1047 public String toString() {
1048 final StringBuffer sb = new StringBuffer();
1049 sb.append("KeyedObjectPoolMinIdleTimerTask");
1050 sb.append("{minIdle=").append(minIdle);
1051 sb.append(", key=").append(key);
1052 sb.append(", keyedPool=").append(keyedPool);
1053 sb.append('}');
1054 return sb.toString();
1055 }
1056 }
1057
1058 private static class SynchronizedObjectPool implements ObjectPool {
1059 private final Object lock;
1060 private final ObjectPool pool;
1061
1062 SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException {
1063 if (pool == null) {
1064 throw new IllegalArgumentException("pool must not be null.");
1065 }
1066 this.pool = pool;
1067 lock = new Object();
1068 }
1069
1070 public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
1071 synchronized (lock) {
1072 return pool.borrowObject();
1073 }
1074 }
1075
1076 public void returnObject(final Object obj) {
1077 synchronized (lock) {
1078 try {
1079 pool.returnObject(obj);
1080 } catch (Exception e) {
1081
1082 }
1083 }
1084 }
1085
1086 public void invalidateObject(final Object obj) {
1087 synchronized (lock) {
1088 try {
1089 pool.invalidateObject(obj);
1090 } catch (Exception e) {
1091
1092 }
1093 }
1094 }
1095
1096 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
1097 synchronized (lock) {
1098 pool.addObject();
1099 }
1100 }
1101
1102 public int getNumIdle() throws UnsupportedOperationException {
1103 synchronized (lock) {
1104 return pool.getNumIdle();
1105 }
1106 }
1107
1108 public int getNumActive() throws UnsupportedOperationException {
1109 synchronized (lock) {
1110 return pool.getNumActive();
1111 }
1112 }
1113
1114 public void clear() throws Exception, UnsupportedOperationException {
1115 synchronized (lock) {
1116 pool.clear();
1117 }
1118 }
1119
1120 public void close() {
1121 try {
1122 synchronized (lock) {
1123 pool.close();
1124 }
1125 } catch (Exception e) {
1126
1127 }
1128 }
1129
1130 public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
1131 synchronized (lock) {
1132 pool.setFactory(factory);
1133 }
1134 }
1135
1136 public String toString() {
1137 final StringBuffer sb = new StringBuffer();
1138 sb.append("SynchronizedObjectPool");
1139 sb.append("{pool=").append(pool);
1140 sb.append('}');
1141 return sb.toString();
1142 }
1143 }
1144
1145 private static class SynchronizedKeyedObjectPool implements KeyedObjectPool {
1146 private final Object lock;
1147 private final KeyedObjectPool keyedPool;
1148
1149 SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
1150 if (keyedPool == null) {
1151 throw new IllegalArgumentException("keyedPool must not be null.");
1152 }
1153 this.keyedPool = keyedPool;
1154 lock = new Object();
1155 }
1156
1157 public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
1158 synchronized (lock) {
1159 return keyedPool.borrowObject(key);
1160 }
1161 }
1162
1163 public void returnObject(final Object key, final Object obj) {
1164 synchronized (lock) {
1165 try {
1166 keyedPool.returnObject(key, obj);
1167 } catch (Exception e) {
1168
1169 }
1170 }
1171 }
1172
1173 public void invalidateObject(final Object key, final Object obj) {
1174 synchronized (lock) {
1175 try {
1176 keyedPool.invalidateObject(key, obj);
1177 } catch (Exception e) {
1178
1179 }
1180 }
1181 }
1182
1183 public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
1184 synchronized (lock) {
1185 keyedPool.addObject(key);
1186 }
1187 }
1188
1189 public int getNumIdle(final Object key) throws UnsupportedOperationException {
1190 synchronized (lock) {
1191 return keyedPool.getNumIdle(key);
1192 }
1193 }
1194
1195 public int getNumActive(final Object key) throws UnsupportedOperationException {
1196 synchronized (lock) {
1197 return keyedPool.getNumActive(key);
1198 }
1199 }
1200
1201 public int getNumIdle() throws UnsupportedOperationException {
1202 synchronized (lock) {
1203 return keyedPool.getNumIdle();
1204 }
1205 }
1206
1207 public int getNumActive() throws UnsupportedOperationException {
1208 synchronized (lock) {
1209 return keyedPool.getNumActive();
1210 }
1211 }
1212
1213 public void clear() throws Exception, UnsupportedOperationException {
1214 synchronized (lock) {
1215 keyedPool.clear();
1216 }
1217 }
1218
1219 public void clear(final Object key) throws Exception, UnsupportedOperationException {
1220 synchronized (lock) {
1221 keyedPool.clear(key);
1222 }
1223 }
1224
1225 public void close() {
1226 try {
1227 synchronized (lock) {
1228 keyedPool.close();
1229 }
1230 } catch (Exception e) {
1231
1232 }
1233 }
1234
1235 public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
1236 synchronized (lock) {
1237 keyedPool.setFactory(factory);
1238 }
1239 }
1240
1241 public String toString() {
1242 final StringBuffer sb = new StringBuffer();
1243 sb.append("SynchronizedKeyedObjectPool");
1244 sb.append("{keyedPool=").append(keyedPool);
1245 sb.append('}');
1246 return sb.toString();
1247 }
1248 }
1249
1250 private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory {
1251 private final Object lock;
1252 private final PoolableObjectFactory factory;
1253
1254 SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException {
1255 if (factory == null) {
1256 throw new IllegalArgumentException("factory must not be null.");
1257 }
1258 this.factory = factory;
1259 lock = new Object();
1260 }
1261
1262 public Object makeObject() throws Exception {
1263 synchronized (lock) {
1264 return factory.makeObject();
1265 }
1266 }
1267
1268 public void destroyObject(final Object obj) throws Exception {
1269 synchronized (lock) {
1270 factory.destroyObject(obj);
1271 }
1272 }
1273
1274 public boolean validateObject(final Object obj) {
1275 synchronized (lock) {
1276 return factory.validateObject(obj);
1277 }
1278 }
1279
1280 public void activateObject(final Object obj) throws Exception {
1281 synchronized (lock) {
1282 factory.activateObject(obj);
1283 }
1284 }
1285
1286 public void passivateObject(final Object obj) throws Exception {
1287 synchronized (lock) {
1288 factory.passivateObject(obj);
1289 }
1290 }
1291
1292 public String toString() {
1293 final StringBuffer sb = new StringBuffer();
1294 sb.append("SynchronizedPoolableObjectFactory");
1295 sb.append("{factory=").append(factory);
1296 sb.append('}');
1297 return sb.toString();
1298 }
1299 }
1300
1301 private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory {
1302 private final Object lock;
1303 private final KeyedPoolableObjectFactory keyedFactory;
1304
1305 SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
1306 if (keyedFactory == null) {
1307 throw new IllegalArgumentException("keyedFactory must not be null.");
1308 }
1309 this.keyedFactory = keyedFactory;
1310 lock = new Object();
1311 }
1312
1313 public Object makeObject(final Object key) throws Exception {
1314 synchronized (lock) {
1315 return keyedFactory.makeObject(key);
1316 }
1317 }
1318
1319 public void destroyObject(final Object key, final Object obj) throws Exception {
1320 synchronized (lock) {
1321 keyedFactory.destroyObject(key, obj);
1322 }
1323 }
1324
1325 public boolean validateObject(final Object key, final Object obj) {
1326 synchronized (lock) {
1327 return keyedFactory.validateObject(key, obj);
1328 }
1329 }
1330
1331 public void activateObject(final Object key, final Object obj) throws Exception {
1332 synchronized (lock) {
1333 keyedFactory.activateObject(key, obj);
1334 }
1335 }
1336
1337 public void passivateObject(final Object key, final Object obj) throws Exception {
1338 synchronized (lock) {
1339 keyedFactory.passivateObject(key, obj);
1340 }
1341 }
1342
1343 public String toString() {
1344 final StringBuffer sb = new StringBuffer();
1345 sb.append("SynchronizedKeyedPoolableObjectFactory");
1346 sb.append("{keyedFactory=").append(keyedFactory);
1347 sb.append('}');
1348 return sb.toString();
1349 }
1350 }
1351
1352 /***
1353 * Encapsulate the logic for when the next poolable object should be discarded.
1354 */
1355 private static class ErodingFactor {
1356 private final float factor;
1357 private transient volatile long nextShrink;
1358 private transient volatile int idleHighWaterMark;
1359
1360 public ErodingFactor(final float factor) {
1361 this.factor = factor;
1362 nextShrink = System.currentTimeMillis() + (long)(900000 * factor);
1363 idleHighWaterMark = 1;
1364 }
1365
1366 public void update(final int numIdle) {
1367 update(System.currentTimeMillis(), numIdle);
1368 }
1369
1370 public void update(final long now, final int numIdle) {
1371 final int idle = Math.max(0, numIdle);
1372 idleHighWaterMark = Math.max(idle, idleHighWaterMark);
1373 final float maxInterval = 15f;
1374 final float minutes = maxInterval + ((1f-maxInterval)/idleHighWaterMark) * idle;
1375 nextShrink = now + (long)(minutes * 60000f * factor);
1376 }
1377
1378 public long getNextShrink() {
1379 return nextShrink;
1380 }
1381
1382 public String toString() {
1383 return "ErodingFactor{" +
1384 "factor=" + factor +
1385 ", idleHighWaterMark=" + idleHighWaterMark +
1386 '}';
1387 }
1388 }
1389
1390 private static class ErodingObjectPool implements ObjectPool {
1391 private final ObjectPool pool;
1392 private final ErodingFactor factor;
1393
1394 public ErodingObjectPool(final ObjectPool pool, final float factor) {
1395 this.pool = pool;
1396 this.factor = new ErodingFactor(factor);
1397 }
1398
1399 public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
1400 return pool.borrowObject();
1401 }
1402
1403 public void returnObject(final Object obj) {
1404 boolean discard = false;
1405 final long now = System.currentTimeMillis();
1406 synchronized (pool) {
1407 if (factor.getNextShrink() < now) {
1408 final int numIdle = pool.getNumIdle();
1409 if (numIdle > 0) {
1410 discard = true;
1411 }
1412
1413 factor.update(now, numIdle);
1414 }
1415 }
1416 try {
1417 if (discard) {
1418 pool.invalidateObject(obj);
1419 } else {
1420 pool.returnObject(obj);
1421 }
1422 } catch (Exception e) {
1423
1424 }
1425 }
1426
1427 public void invalidateObject(final Object obj) {
1428 try {
1429 pool.invalidateObject(obj);
1430 } catch (Exception e) {
1431
1432 }
1433 }
1434
1435 public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
1436 pool.addObject();
1437 }
1438
1439 public int getNumIdle() throws UnsupportedOperationException {
1440 return pool.getNumIdle();
1441 }
1442
1443 public int getNumActive() throws UnsupportedOperationException {
1444 return pool.getNumActive();
1445 }
1446
1447 public void clear() throws Exception, UnsupportedOperationException {
1448 pool.clear();
1449 }
1450
1451 public void close() {
1452 try {
1453 pool.close();
1454 } catch (Exception e) {
1455
1456 }
1457 }
1458
1459 public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
1460 pool.setFactory(factory);
1461 }
1462
1463 public String toString() {
1464 return "ErodingObjectPool{" +
1465 "factor=" + factor +
1466 ", pool=" + pool +
1467 '}';
1468 }
1469 }
1470
1471 private static class ErodingKeyedObjectPool implements KeyedObjectPool {
1472 private final KeyedObjectPool keyedPool;
1473 private final ErodingFactor erodingFactor;
1474
1475 public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) {
1476 this(keyedPool, new ErodingFactor(factor));
1477 }
1478
1479 protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final ErodingFactor erodingFactor) {
1480 if (keyedPool == null) {
1481 throw new IllegalArgumentException("keyedPool must not be null.");
1482 }
1483 this.keyedPool = keyedPool;
1484 this.erodingFactor = erodingFactor;
1485 }
1486
1487 public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
1488 return keyedPool.borrowObject(key);
1489 }
1490
1491 public void returnObject(final Object key, final Object obj) throws Exception {
1492 boolean discard = false;
1493 final long now = System.currentTimeMillis();
1494 final ErodingFactor factor = getErodingFactor(key);
1495 synchronized (keyedPool) {
1496 if (factor.getNextShrink() < now) {
1497 final int numIdle = numIdle(key);
1498 if (numIdle > 0) {
1499 discard = true;
1500 }
1501
1502 factor.update(now, numIdle);
1503 }
1504 }
1505 try {
1506 if (discard) {
1507 keyedPool.invalidateObject(key, obj);
1508 } else {
1509 keyedPool.returnObject(key, obj);
1510 }
1511 } catch (Exception e) {
1512
1513 }
1514 }
1515
1516 protected int numIdle(final Object key) {
1517 return getKeyedPool().getNumIdle();
1518 }
1519
1520 protected ErodingFactor getErodingFactor(final Object key) {
1521 return erodingFactor;
1522 }
1523
1524 public void invalidateObject(final Object key, final Object obj) {
1525 try {
1526 keyedPool.invalidateObject(key, obj);
1527 } catch (Exception e) {
1528
1529 }
1530 }
1531
1532 public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
1533 keyedPool.addObject(key);
1534 }
1535
1536 public int getNumIdle() throws UnsupportedOperationException {
1537 return keyedPool.getNumIdle();
1538 }
1539
1540 public int getNumIdle(final Object key) throws UnsupportedOperationException {
1541 return keyedPool.getNumIdle(key);
1542 }
1543
1544 public int getNumActive() throws UnsupportedOperationException {
1545 return keyedPool.getNumActive();
1546 }
1547
1548 public int getNumActive(final Object key) throws UnsupportedOperationException {
1549 return keyedPool.getNumActive(key);
1550 }
1551
1552 public void clear() throws Exception, UnsupportedOperationException {
1553 keyedPool.clear();
1554 }
1555
1556 public void clear(final Object key) throws Exception, UnsupportedOperationException {
1557 keyedPool.clear(key);
1558 }
1559
1560 public void close() {
1561 try {
1562 keyedPool.close();
1563 } catch (Exception e) {
1564
1565 }
1566 }
1567
1568 public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
1569 keyedPool.setFactory(factory);
1570 }
1571
1572 protected KeyedObjectPool getKeyedPool() {
1573 return keyedPool;
1574 }
1575
1576 public String toString() {
1577 return "ErodingKeyedObjectPool{" +
1578 "erodingFactor=" + erodingFactor +
1579 ", keyedPool=" + keyedPool +
1580 '}';
1581 }
1582 }
1583
1584 private static class ErodingPerKeyKeyedObjectPool extends ErodingKeyedObjectPool {
1585 private final float factor;
1586 private final Map factors = Collections.synchronizedMap(new HashMap());
1587
1588 public ErodingPerKeyKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) {
1589 super(keyedPool, null);
1590 this.factor = factor;
1591 }
1592
1593 protected int numIdle(final Object key) {
1594 return getKeyedPool().getNumIdle(key);
1595 }
1596
1597 protected ErodingFactor getErodingFactor(final Object key) {
1598 ErodingFactor factor = (ErodingFactor)factors.get(key);
1599
1600
1601 if (factor == null) {
1602 factor = new ErodingFactor(this.factor);
1603 factors.put(key, factor);
1604 }
1605 return factor;
1606 }
1607
1608 public String toString() {
1609 return "ErodingPerKeyKeyedObjectPool{" +
1610 "factor=" + factor +
1611 ", keyedPool=" + getKeyedPool() +
1612 '}';
1613 }
1614 }
1615 }