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