001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.commons.pool;
019    
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.HashMap;
023    import java.util.Iterator;
024    import java.util.Map;
025    import java.util.NoSuchElementException;
026    import java.util.Timer;
027    import java.util.TimerTask;
028    
029    /**
030     * This class consists exclusively of static methods that operate on or return ObjectPool
031     * or KeyedObjectPool related interfaces.
032     *
033     * @author Sandy McArthur
034     * @version $Revision: 1222670 $ $Date: 2011-12-23 08:18:25 -0500 (Fri, 23 Dec 2011) $
035     * @since Pool 1.3
036     */
037    public final class PoolUtils {
038    
039        /**
040         * Timer used to periodically check pools idle object count.
041         * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated.
042         */
043        private static Timer MIN_IDLE_TIMER; //@GuardedBy("this")
044    
045        /**
046         * PoolUtils instances should NOT be constructed in standard programming.
047         * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
048         * This constructor is public to permit tools that require a JavaBean instance to operate.
049         */
050        public PoolUtils() {
051        }
052    
053        /**
054         * Should the supplied Throwable be re-thrown (eg if it is an instance of
055         * one of the Throwables that should never be swallowed). Used by the pool
056         * error handling for operations that throw exceptions that normally need to
057         * be ignored.
058         * @param t The Throwable to check
059         * @throws ThreadDeath if that is passed in
060         * @throws VirtualMachineError if that is passed in
061         * @since Pool 1.5.5
062         */
063        public static void checkRethrow(Throwable t) {
064            if (t instanceof ThreadDeath) {
065                throw (ThreadDeath) t;
066            }
067            if (t instanceof VirtualMachineError) {
068                throw (VirtualMachineError) t;
069            }
070            // All other instances of Throwable will be silently swallowed
071        }
072    
073        /**
074         * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
075         * needed. This method is the equivalent of calling
076         * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}.
077         *
078         * @param <V> the type of object
079         * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
080         * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key.
081         * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>.
082         * @see #adapt(KeyedPoolableObjectFactory, Object)
083         * @since Pool 1.3
084         */
085        public static <V> PoolableObjectFactory<V> adapt(final KeyedPoolableObjectFactory<Object, V> keyedFactory) throws IllegalArgumentException {
086            return adapt(keyedFactory, new Object());
087        }
088    
089        /**
090         * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
091         * needed using the specified <code>key</code> when delegating.
092         *
093         * @param <K> the type of key
094         * @param <V> the type of object
095         * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
096         * @param key the key to use when delegating.
097         * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key.
098         * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>.
099         * @see #adapt(KeyedPoolableObjectFactory)
100         * @since Pool 1.3
101         */
102        public static <K, V> PoolableObjectFactory<V> adapt(final KeyedPoolableObjectFactory<K, V> keyedFactory, final K key) throws IllegalArgumentException {
103            return new PoolableObjectFactoryAdaptor<K, V>(keyedFactory, key);
104        }
105    
106        /**
107         * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is
108         * needed. The key is ignored.
109         *
110         * @param <K> the type of key
111         * @param <V> the type of object
112         * @param factory the {@link PoolableObjectFactory} to delegate to.
113         * @return a {@link KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key.
114         * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>.
115         * @since Pool 1.3
116         */
117        public static <K, V> KeyedPoolableObjectFactory<K, V> adapt(final PoolableObjectFactory<V> factory) throws IllegalArgumentException {
118            return new KeyedPoolableObjectFactoryAdaptor<K, V>(factory);
119        }
120    
121        /**
122         * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the
123         * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}.
124         *
125         * @param <V> the type of object
126         * @param keyedPool the {@link KeyedObjectPool} to delegate to.
127         * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with an internal key.
128         * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>.
129         * @see #adapt(KeyedObjectPool, Object)
130         * @since Pool 1.3
131         */
132        public static <V> ObjectPool<V> adapt(final KeyedObjectPool<Object, V> keyedPool) throws IllegalArgumentException {
133            return adapt(keyedPool, new Object());
134        }
135    
136        /**
137         * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the
138         * specified <code>key</code> when delegating.
139         *
140         * @param <V> the type of object
141         * @param keyedPool the {@link KeyedObjectPool} to delegate to.
142         * @param key the key to use when delegating.
143         * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with the specified key.
144         * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
145         * @see #adapt(KeyedObjectPool)
146         * @since Pool 1.3
147         */
148        public static <V> ObjectPool<V> adapt(final KeyedObjectPool<Object, V> keyedPool, final Object key) throws IllegalArgumentException {
149            return new ObjectPoolAdaptor<V>(keyedPool, key);
150        }
151    
152        /**
153         * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed.
154         * The key is ignored.
155         *
156         * @param <K> the type of key
157         * @param <V> the type of object
158         * @param pool the {@link ObjectPool} to delegate to.
159         * @return a {@link KeyedObjectPool} that delegates to <code>pool</code> ignoring the key.
160         * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>.
161         * @since Pool 1.3
162         */
163        public static <K, V> KeyedObjectPool<K, V> adapt(final ObjectPool<V> pool) throws IllegalArgumentException {
164            return new KeyedObjectPoolAdaptor<K, V>(pool);
165        }
166    
167        /**
168         * Wraps an <code>ObjectPool</code> and dynamically checks the type of objects borrowed and returned to the pool.
169         * If an object is passed to the pool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
170         *
171         * @param <T> the type of object
172         * @param pool the pool to enforce type safety on
173         * @param type the class type to enforce.
174         * @return an <code>ObjectPool</code> that will only allow objects of <code>type</code>
175         * @since Pool 1.3
176         */
177        public static <T> ObjectPool<T> checkedPool(final ObjectPool<T> pool, final Class<T> type) {
178            if (pool == null) {
179                throw new IllegalArgumentException("pool must not be null.");
180            }
181            if (type == null) {
182                throw new IllegalArgumentException("type must not be null.");
183            }
184            return new CheckedObjectPool<T>(pool, type);
185        }
186    
187        /**
188         * Wraps a <code>KeyedObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool.
189         * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
190         *
191         * @param <K> the type of key
192         * @param <V> the type of object
193         * @param keyedPool the keyedPool to enforce type safety on
194         * @param type the class type to enforce.
195         * @return a <code>KeyedObjectPool</code> that will only allow objects of <code>type</code>
196         * @since Pool 1.3
197         */
198        public static <K, V> KeyedObjectPool<K, V> checkedPool(final KeyedObjectPool<K, V> keyedPool, final Class<V> type) {
199            if (keyedPool == null) {
200                throw new IllegalArgumentException("keyedPool must not be null.");
201            }
202            if (type == null) {
203                throw new IllegalArgumentException("type must not be null.");
204            }
205            return new CheckedKeyedObjectPool<K, V>(keyedPool, type);
206        }
207    
208        /**
209         * Periodically check the idle object count for the pool. At most one idle object will be added per period.
210         * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed.
211         *
212         * @param <T> the type of object
213         * @param pool the pool to check periodically.
214         * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object.
215         * @param period the frequency to check the number of idle objects in a pool, see
216         *      {@link Timer#schedule(TimerTask, long, long)}.
217         * @return the {@link TimerTask} that will periodically check the pools idle object count.
218         * @throws IllegalArgumentException when <code>pool</code> is <code>null</code> or
219         *      when <code>minIdle</code> is negative or when <code>period</code> isn't
220         *      valid for {@link Timer#schedule(TimerTask, long, long)}.
221         * @since Pool 1.3
222         */
223        public static <T> TimerTask checkMinIdle(final ObjectPool<T> pool, final int minIdle, final long period) throws IllegalArgumentException {
224            if (pool == null) {
225                throw new IllegalArgumentException("keyedPool must not be null.");
226            }
227            if (minIdle < 0) {
228                throw new IllegalArgumentException("minIdle must be non-negative.");
229            }
230            final TimerTask task = new ObjectPoolMinIdleTimerTask<T>(pool, minIdle);
231            getMinIdleTimer().schedule(task, 0L, period);
232            return task;
233        }
234    
235        /**
236         * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period.
237         * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key
238         * will be performed.
239         *
240         * @param <K> the type of key
241         * @param <V> the type of object
242         * @param keyedPool the keyedPool to check periodically.
243         * @param key the key to check the idle count of.
244         * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
245         * @param period the frequency to check the number of idle objects in a keyedPool, see
246         *      {@link Timer#schedule(TimerTask, long, long)}.
247         * @return the {@link TimerTask} that will periodically check the pools idle object count.
248         * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or
249         *      when <code>minIdle</code> is negative or when <code>period</code> isn't
250         *      valid for {@link Timer#schedule(TimerTask, long, long)}.
251         * @since Pool 1.3
252         */
253        public static <K, V> TimerTask checkMinIdle(final KeyedObjectPool<K, V> keyedPool, final K key, final int minIdle, final long period) throws IllegalArgumentException {
254            if (keyedPool == null) {
255                throw new IllegalArgumentException("keyedPool must not be null.");
256            }
257            if (key == null) {
258                throw new IllegalArgumentException("key must not be null.");
259            }
260            if (minIdle < 0) {
261                throw new IllegalArgumentException("minIdle must be non-negative.");
262            }
263            final TimerTask task = new KeyedObjectPoolMinIdleTimerTask<K, V>(keyedPool, key, minIdle);
264            getMinIdleTimer().schedule(task, 0L, period);
265            return task;
266        }
267    
268        /**
269         * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the keyedPool.
270         * At most one idle object will be added per period.
271         *
272         * @param <K> the type of key
273         * @param <V> the type of object
274         * @param keyedPool the keyedPool to check periodically.
275         * @param keys a collection of keys to check the idle object count.
276         * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
277         * @param period the frequency to check the number of idle objects in a keyedPool, see
278         *      {@link Timer#schedule(TimerTask, long, long)}.
279         * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count.
280         * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the
281         *      collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't
282         *      valid for {@link Timer#schedule(TimerTask, long, long)}.
283         * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
284         * @since Pool 1.3
285         */
286        public static <K, V> Map<K, TimerTask> checkMinIdle(final KeyedObjectPool<K, V> keyedPool, final Collection<? extends K> keys, final int minIdle, final long period) throws IllegalArgumentException {
287            if (keys == null) {
288                throw new IllegalArgumentException("keys must not be null.");
289            }
290            final Map<K, TimerTask> tasks = new HashMap<K, TimerTask>(keys.size());
291            final Iterator<? extends K> iter = keys.iterator();
292            while (iter.hasNext()) {
293                final K key = iter.next();
294                final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
295                tasks.put(key, task);
296            }
297            return tasks;
298        }
299    
300        /**
301         * Call <code>addObject()</code> on <code>pool</code> <code>count</code> number of times.
302         *
303         * @param <T> the type of object
304         * @param pool the pool to prefill.
305         * @param count the number of idle objects to add.
306         * @throws Exception when {@link ObjectPool#addObject()} fails.
307         * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>.
308         * @since Pool 1.3
309         */
310        public static <T> void prefill(final ObjectPool<T> pool, final int count) throws Exception, IllegalArgumentException {
311            if (pool == null) {
312                throw new IllegalArgumentException("pool must not be null.");
313            }
314            for (int i = 0; i < count; i++) {
315                pool.addObject();
316            }
317        }
318    
319        /**
320         * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code>
321         * number of times.
322         *
323         * @param <K> the type of key
324         * @param <V> the type of object
325         * @param keyedPool the keyedPool to prefill.
326         * @param key the key to add objects for.
327         * @param count the number of idle objects to add for <code>key</code>.
328         * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
329         * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
330         * @since Pool 1.3
331         */
332        public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool, final K key, final int count) throws Exception, IllegalArgumentException {
333            if (keyedPool == null) {
334                throw new IllegalArgumentException("keyedPool must not be null.");
335            }
336            if (key == null) {
337                throw new IllegalArgumentException("key must not be null.");
338            }
339            for (int i = 0; i < count; i++) {
340                keyedPool.addObject(key);
341            }
342        }
343    
344        /**
345         * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for
346         * <code>count</code> number of times. This has the same effect as calling
347         * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection.
348         *
349         * @param <K> the type of key
350         * @param <V> the type of object
351         * @param keyedPool the keyedPool to prefill.
352         * @param keys {@link Collection} of keys to add objects for.
353         * @param count the number of idle objects to add for each <code>key</code>.
354         * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
355         * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or
356         *      any value in <code>keys</code> is <code>null</code>.
357         * @see #prefill(KeyedObjectPool, Object, int)
358         * @since Pool 1.3
359         */
360        public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool, final Collection<? extends K> keys, final int count) throws Exception, IllegalArgumentException {
361            if (keys == null) {
362                throw new IllegalArgumentException("keys must not be null.");
363            }
364            final Iterator<? extends K> iter = keys.iterator();
365            while (iter.hasNext()) {
366                prefill(keyedPool, iter.next(), count);
367            }
368        }
369    
370        /**
371         * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool.
372         *
373         * <p><b>Note:</b>
374         * This should not be used on pool implementations that already provide proper synchronization
375         * such as the pools provided in the Commons Pool library. Wrapping a pool that
376         * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
377         * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
378         * </p>
379         *
380         * @param <T> the type of object
381         * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool.
382         * @return a synchronized view of the specified ObjectPool.
383         * @since Pool 1.3
384         */
385        public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
386            if (pool == null) {
387                throw new IllegalArgumentException("pool must not be null.");
388            }
389            /*
390            assert !(pool instanceof GenericObjectPool)
391                    : "GenericObjectPool is already thread-safe";
392            assert !(pool instanceof SoftReferenceObjectPool)
393                    : "SoftReferenceObjectPool is already thread-safe";
394            assert !(pool instanceof StackObjectPool)
395                    : "StackObjectPool is already thread-safe";
396            assert !"org.apache.commons.pool.composite.CompositeObjectPool".equals(pool.getClass().getName())
397                    : "CompositeObjectPools are already thread-safe";
398            */
399            return new SynchronizedObjectPool<T>(pool);
400        }
401    
402        /**
403         * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool.
404         *
405         * <p><b>Note:</b>
406         * This should not be used on pool implementations that already provide proper synchronization
407         * such as the pools provided in the Commons Pool library. Wrapping a pool that
408         * {@link #wait() waits} for poolable objects to be returned before allowing another one to be
409         * borrowed with another layer of synchronization will cause liveliness issues or a deadlock.
410         * </p>
411         *
412         * @param <K> the type of key
413         * @param <V> the type of object
414         * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool.
415         * @return a synchronized view of the specified KeyedObjectPool.
416         * @since Pool 1.3
417         */
418        public static <K, V> KeyedObjectPool<K, V> synchronizedPool(final KeyedObjectPool<K, V> keyedPool) {
419            if (keyedPool == null) {
420                throw new IllegalArgumentException("keyedPool must not be null.");
421            }
422            /*
423            assert !(keyedPool instanceof GenericKeyedObjectPool)
424                    : "GenericKeyedObjectPool is already thread-safe";
425            assert !(keyedPool instanceof StackKeyedObjectPool)
426                    : "StackKeyedObjectPool is already thread-safe";
427            assert !"org.apache.commons.pool.composite.CompositeKeyedObjectPool".equals(keyedPool.getClass().getName())
428                    : "CompositeKeyedObjectPools are already thread-safe";
429            */
430            return new SynchronizedKeyedObjectPool<K, V>(keyedPool);
431        }
432    
433        /**
434         * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory.
435         *
436         * @param <T> the type of object
437         * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory.
438         * @return a synchronized view of the specified PoolableObjectFactory.
439         * @since Pool 1.3
440         */
441        public static <T> PoolableObjectFactory<T> synchronizedPoolableFactory(final PoolableObjectFactory<T> factory) {
442            return new SynchronizedPoolableObjectFactory<T>(factory);
443        }
444    
445        /**
446         * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory.
447         *
448         * @param <K> the type of key
449         * @param <V> the type of object
450         * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory.
451         * @return a synchronized view of the specified KeyedPoolableObjectFactory.
452         * @since Pool 1.3
453         */
454        public static <K, V> KeyedPoolableObjectFactory<K, V> synchronizedPoolableFactory(final KeyedPoolableObjectFactory<K, V> keyedFactory) {
455            return new SynchronizedKeyedPoolableObjectFactory<K, V>(keyedFactory);
456        }
457    
458        /**
459         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
460         * This is intended as an always thread-safe alternative to using an idle object evictor
461         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
462         * pools that experience load spikes.
463         *
464         * @param <T> the type of object
465         * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible.
466         * @return a pool that adaptively decreases it's size when idle objects are no longer needed.
467         * @see #erodingPool(ObjectPool, float)
468         * @since Pool 1.4
469         */
470        public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
471            return erodingPool(pool, 1f);
472        }
473    
474        /**
475         * Returns a pool that adaptively decreases it's size when idle objects are no longer needed.
476         * This is intended as an always thread-safe alternative to using an idle object evictor
477         * provided by many pool implementations. This is also an effective way to shrink FIFO ordered
478         * pools that experience load spikes.
479         *
480         * <p>
481         * The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink
482         * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often.
483         * Values greater than 1 cause the pool to less frequently try to shrink it's size.
484         * </p>
485         *
486         * @param <T> the type of object
487         * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible.
488         * @param factor a positive value to scale the rate at which the pool tries to reduce it's size.
489         * If 0 &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    }