View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.pool;
19  
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.Map;
25  import java.util.NoSuchElementException;
26  import java.util.Timer;
27  import java.util.TimerTask;
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: 1222670 $ $Date: 2011-12-23 08:18:25 -0500 (Fri, 23 Dec 2011) $
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; //@GuardedBy("this")
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       * Should the supplied Throwable be re-thrown (eg if it is an instance of
55       * one of the Throwables that should never be swallowed). Used by the pool
56       * error handling for operations that throw exceptions that normally need to
57       * be ignored.
58       * @param t The Throwable to check
59       * @throws ThreadDeath if that is passed in
60       * @throws VirtualMachineError if that is passed in
61       * @since Pool 1.5.5
62       */
63      public static void checkRethrow(Throwable t) {
64          if (t instanceof ThreadDeath) {
65              throw (ThreadDeath) t;
66          }
67          if (t instanceof VirtualMachineError) {
68              throw (VirtualMachineError) t;
69          }
70          // All other instances of Throwable will be silently swallowed
71      }
72  
73      /**
74       * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
75       * needed. This method is the equivalent of calling
76       * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}.
77       *
78       * @param <V> the type of object
79       * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
80       * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key.
81       * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>.
82       * @see #adapt(KeyedPoolableObjectFactory, Object)
83       * @since Pool 1.3
84       */
85      public static <V> PoolableObjectFactory<V> adapt(final KeyedPoolableObjectFactory<Object, V> keyedFactory) throws IllegalArgumentException {
86          return adapt(keyedFactory, new Object());
87      }
88  
89      /**
90       * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
91       * needed using the specified <code>key</code> when delegating.
92       *
93       * @param <K> the type of key
94       * @param <V> the type of object
95       * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
96       * @param key the key to use when delegating.
97       * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key.
98       * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>.
99       * @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 &lt; factor &lt; 1 then the pool shrinks more aggressively.
490      * If 1 &lt; 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 &lt; factor &lt; 1 then the pool shrinks more aggressively.
542      * If 1 &lt; 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 &lt; factor &lt; 1 then the pool shrinks more aggressively.
575      * If 1 &lt; 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 }