View Javadoc

1   /*
2    * Copyright 2006 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.pool;
18  
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Iterator;
22  import java.util.Map;
23  import java.util.NoSuchElementException;
24  import java.util.Timer;
25  import java.util.TimerTask;
26  
27  /***
28   * This class consists exclusively of static methods that operate on or return keyedPool related interfaces.
29   *
30   * @author Sandy McArthur
31   * @version $Revision: 385296 $ $Date: 2006-03-12 10:28:08 -0500 (Sun, 12 Mar 2006) $
32   * @since Pool 1.3
33   */
34  public final class PoolUtils {
35  
36      /***
37       * Timer used to periodically check pools idle object count.
38       * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated.
39       */
40      private static Timer MIN_IDLE_TIMER;
41  
42      /***
43       * PoolUtils instances should NOT be constructed in standard programming.
44       * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
45       * This constructor is public to permit tools that require a JavaBean instance to operate.
46       */
47      public PoolUtils() {
48      }
49  
50      /***
51       * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
52       * needed. This method is the equivalent of calling
53       * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}.
54       *
55       * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
56       * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key.
57       * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>.
58       * @see #adapt(KeyedPoolableObjectFactory, Object)
59       * @since Pool 1.3
60       */
61      public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
62          return adapt(keyedFactory, new Object());
63      }
64  
65      /***
66       * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is
67       * needed using the specified <code>key</code> when delegating.
68       *
69       * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
70       * @param key the key to use when delegating.
71       * @return a {@link PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key.
72       * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>.
73       * @see #adapt(KeyedPoolableObjectFactory)
74       * @since Pool 1.3
75       */
76      public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException {
77          return new PoolableObjectFactoryAdaptor(keyedFactory, key);
78      }
79  
80      /***
81       * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is
82       * needed. The key is ignored.
83       *
84       * @param factory the {@link PoolableObjectFactory} to delegate to.
85       * @return a {@link KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key.
86       * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>.
87       * @since Pool 1.3
88       */
89      public static KeyedPoolableObjectFactory adapt(final PoolableObjectFactory factory) throws IllegalArgumentException {
90          return new KeyedPoolableObjectFactoryAdaptor(factory);
91      }
92  
93      /***
94       * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the
95       * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}.
96       *
97       * @param keyedPool the {@link KeyedObjectPool} to delegate to.
98       * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with an internal key.
99       * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>.
100      * @see #adapt(KeyedObjectPool, Object)
101      * @since Pool 1.3
102      */
103     public static ObjectPool adapt(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
104         return adapt(keyedPool, new Object());
105     }
106 
107     /***
108      * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the
109      * specified <code>key</code> when delegating.
110      *
111      * @param keyedPool the {@link KeyedObjectPool} to delegate to.
112      * @param key the key to use when delegating.
113      * @return an {@link ObjectPool} that delegates to <code>keyedPool</code> with the specified key.
114      * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
115      * @see #adapt(KeyedObjectPool)
116      * @since Pool 1.3
117      */
118     public static ObjectPool adapt(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
119         return new ObjectPoolAdaptor(keyedPool, key);
120     }
121 
122     /***
123      * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed.
124      * The key is ignored.
125      *
126      * @param pool the {@link ObjectPool} to delegate to.
127      * @return a {@link KeyedObjectPool} that delegates to <code>keyedPool</code> ignoring the key.
128      * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>.
129      * @since Pool 1.3
130      */
131     public static KeyedObjectPool adapt(final ObjectPool pool) throws IllegalArgumentException {
132         return new KeyedObjectPoolAdaptor(pool);
133     }
134 
135     /***
136      * Wraps an <code>ObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool.
137      * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
138      *
139      * @param pool the keyedPool to enforce type safety on
140      * @return an <code>ObjectPool</code> that will only allow objects of <code>type</code>
141      * @since Pool 1.3
142      */
143     public static ObjectPool checkedPool(final ObjectPool pool, final Class type) {
144         if (pool == null) {
145             throw new IllegalArgumentException("pool must not be null.");
146         }
147         if (type == null) {
148             throw new IllegalArgumentException("type must not be null.");
149         }
150         return new CheckedObjectPool(pool, type);
151     }
152 
153     /***
154      * Wraps an <code>KeyedObjectPool</code> and dynamically checks the type of objects borrowed and returned to the keyedPool.
155      * If an object is passed to the keyedPool that isn't of type <code>type</code> a {@link ClassCastException} will be thrown.
156      *
157      * @param keyedPool the keyedPool to enforce type safety on
158      * @return an <code>KeyedObjectPool</code> that will only allow objects of <code>type</code>
159      * @since Pool 1.3
160      */
161     public static KeyedObjectPool checkedPool(final KeyedObjectPool keyedPool, final Class type) {
162         if (keyedPool == null) {
163             throw new IllegalArgumentException("keyedPool must not be null.");
164         }
165         if (type == null) {
166             throw new IllegalArgumentException("type must not be null.");
167         }
168         return new CheckedKeyedObjectPool(keyedPool, type);
169     }
170 
171     /***
172      * Periodically check the idle object count for the keyedPool. At most one idle object will be added per period.
173      * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed.
174      *
175      * @param pool the keyedPool to check periodically.
176      * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object.
177      * @param period the frequency to check the number of idle objects in a keyedPool, see
178      *      {@link Timer#schedule(TimerTask, long, long)}.
179      * @return the {@link TimerTask} that will periodically check the pools idle object count.
180      * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code> or
181      *      when <code>minIdle</code> is negative or when <code>period</code> isn't
182      *      valid for {@link Timer#schedule(TimerTask, long, long)}.
183      * @since Pool 1.3
184      */
185     public static TimerTask checkMinIdle(final ObjectPool pool, final int minIdle, final long period) throws IllegalArgumentException {
186         if (pool == null) {
187             throw new IllegalArgumentException("keyedPool must not be null.");
188         }
189         if (minIdle < 0) {
190             throw new IllegalArgumentException("minIdle must be non-negative.");
191         }
192         final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle);
193         getMinIdleTimer().schedule(task, 0L, period);
194         return task;
195     }
196 
197     /***
198      * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period.
199      * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key
200      * will be performed.
201      *
202      * @param keyedPool the keyedPool to check periodically.
203      * @param key the key to check the idle count of.
204      * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
205      * @param period the frequency to check the number of idle objects in a keyedPool, see
206      *      {@link Timer#schedule(TimerTask, long, long)}.
207      * @return the {@link TimerTask} that will periodically check the pools idle object count.
208      * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or
209      *      when <code>minIdle</code> is negative or when <code>period</code> isn't
210      *      valid for {@link Timer#schedule(TimerTask, long, long)}.
211      * @since Pool 1.3
212      */
213     public static TimerTask checkMinIdle(final KeyedObjectPool keyedPool, final Object key, final int minIdle, final long period) throws IllegalArgumentException {
214         if (keyedPool == null) {
215             throw new IllegalArgumentException("keyedPool must not be null.");
216         }
217         if (key == null) {
218             throw new IllegalArgumentException("key must not be null.");
219         }
220         if (minIdle < 0) {
221             throw new IllegalArgumentException("minIdle must be non-negative.");
222         }
223         final TimerTask task = new KeyedObjectPoolMinIdleTimerTask(keyedPool, key, minIdle);
224         getMinIdleTimer().schedule(task, 0L, period);
225         return task;
226     }
227 
228     /***
229      * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the keyedPool.
230      * At most one idle object will be added per period.
231      *
232      * @param keyedPool the keyedPool to check periodically.
233      * @param keys a collection of keys to check the idle object count.
234      * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
235      * @param period the frequency to check the number of idle objects in a keyedPool, see
236      *      {@link Timer#schedule(TimerTask, long, long)}.
237      * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count.
238      * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the
239      *      collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't
240      *      valid for {@link Timer#schedule(TimerTask, long, long)}.
241      * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
242      * @since Pool 1.3
243      */
244     public static Map checkMinIdle(final KeyedObjectPool keyedPool, final Collection keys, final int minIdle, final long period) throws IllegalArgumentException {
245         if (keys == null) {
246             throw new IllegalArgumentException("keys must not be null.");
247         }
248         final Map tasks = new HashMap(keys.size());
249         final Iterator iter = keys.iterator();
250         while (iter.hasNext()) {
251             final Object key = iter.next();
252             final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
253             tasks.put(key, task);
254         }
255         return tasks;
256     }
257 
258     /***
259      * Call <code>addObject()</code> on <code>keyedPool</code> <code>count</code> number of times.
260      *
261      * @param pool the keyedPool to prefill.
262      * @param count the number of idle objects to add.
263      * @throws Exception when {@link ObjectPool#addObject()} fails.
264      * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>.
265      * @since Pool 1.3
266      */
267     public static void prefill(final ObjectPool pool, final int count) throws Exception, IllegalArgumentException {
268         if (pool == null) {
269             throw new IllegalArgumentException("keyedPool must not be null.");
270         }
271         for (int i = 0; i < count; i++) {
272             pool.addObject();
273         }
274     }
275 
276     /***
277      * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code>
278      * number of times.
279      *
280      * @param keyedPool the keyedPool to prefill.
281      * @param key the key to add objects for.
282      * @param count the number of idle objects to add for <code>key</code>.
283      * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
284      * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>.
285      * @since Pool 1.3
286      */
287     public static void prefill(final KeyedObjectPool keyedPool, final Object key, final int count) throws Exception, IllegalArgumentException {
288         if (keyedPool == null) {
289             throw new IllegalArgumentException("keyedPool must not be null.");
290         }
291         if (key == null) {
292             throw new IllegalArgumentException("key must not be null.");
293         }
294         for (int i = 0; i < count; i++) {
295             keyedPool.addObject(key);
296         }
297     }
298 
299     /***
300      * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for
301      * <code>count</code> number of times. This has the same effect as calling
302      * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection.
303      *
304      * @param keyedPool the keyedPool to prefill.
305      * @param keys {@link Collection} of keys to add objects for.
306      * @param count the number of idle objects to add for each <code>key</code>.
307      * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
308      * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or
309      *      any value in <code>keys</code> is <code>null</code>.
310      * @see #prefill(KeyedObjectPool, Object, int)
311      * @since Pool 1.3
312      */
313     public static void prefill(final KeyedObjectPool keyedPool, final Collection keys, final int count) throws Exception, IllegalArgumentException {
314         if (keys == null) {
315             throw new IllegalArgumentException("keys must not be null.");
316         }
317         final Iterator iter = keys.iterator();
318         while (iter.hasNext()) {
319             prefill(keyedPool, iter.next(), count);
320         }
321     }
322 
323     /***
324      * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool.
325      *
326      * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool.
327      * @return a synchronized view of the specified ObjectPool.
328      * @since Pool 1.3
329      */
330     public static ObjectPool synchronizedPool(final ObjectPool pool) {
331         return new SynchronizedObjectPool(pool);
332     }
333 
334     /***
335      * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool.
336      * 
337      * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool.
338      * @return a synchronized view of the specified KeyedObjectPool.
339      * @since Pool 1.3
340      */
341     public static KeyedObjectPool synchronizedPool(final KeyedObjectPool keyedPool) {
342         return new SynchronizedKeyedObjectPool(keyedPool);
343     }
344 
345     /***
346      * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory.
347      *
348      * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory.
349      * @return a synchronized view of the specified PoolableObjectFactory.
350      * @since Pool 1.3
351      */
352     public static PoolableObjectFactory synchronizedPoolableFactory(final PoolableObjectFactory factory) {
353         return new SynchronizedPoolableObjectFactory(factory);
354     }
355 
356     /***
357      * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory.
358      *
359      * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory.
360      * @return a synchronized view of the specified KeyedPoolableObjectFactory.
361      * @since Pool 1.3
362      */
363     public static KeyedPoolableObjectFactory synchronizedPoolableFactory(final KeyedPoolableObjectFactory keyedFactory) {
364         return new SynchronizedKeyedPoolableObjectFactory(keyedFactory);
365     }
366 
367     /***
368      * Get the <code>Timer</code> for checking keyedPool's idle count. Lazily create the {@link Timer} as needed.
369      *
370      * @return the {@link Timer} for checking keyedPool's idle count.
371      * @since Pool 1.3
372      */
373     private static synchronized Timer getMinIdleTimer() {
374         if (MIN_IDLE_TIMER == null) {
375             MIN_IDLE_TIMER = new Timer(true);
376         }
377         return MIN_IDLE_TIMER;
378     }
379 
380     private static class PoolableObjectFactoryAdaptor implements PoolableObjectFactory {
381         private final Object key;
382         private final KeyedPoolableObjectFactory keyedFactory;
383 
384         PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException {
385             if (keyedFactory == null) {
386                 throw new IllegalArgumentException("keyedFactory must not be null.");
387             }
388             if (key == null) {
389                 throw new IllegalArgumentException("key must not be null.");
390             }
391             this.keyedFactory = keyedFactory;
392             this.key = key;
393         }
394 
395         public Object makeObject() throws Exception {
396             return keyedFactory.makeObject(key);
397         }
398 
399         public void destroyObject(final Object obj) throws Exception {
400             keyedFactory.destroyObject(key, obj);
401         }
402 
403         public boolean validateObject(final Object obj) {
404             return keyedFactory.validateObject(key, obj);
405         }
406 
407         public void activateObject(final Object obj) throws Exception {
408             keyedFactory.activateObject(key, obj);
409         }
410 
411         public void passivateObject(final Object obj) throws Exception {
412             keyedFactory.passivateObject(key, obj);
413         }
414 
415         public String toString() {
416             final StringBuffer sb = new StringBuffer();
417             sb.append("PoolableObjectFactoryAdaptor");
418             sb.append("{key=").append(key);
419             sb.append(", keyedFactory=").append(keyedFactory);
420             sb.append('}');
421             return sb.toString();
422         }
423     }
424 
425     private static class KeyedPoolableObjectFactoryAdaptor implements KeyedPoolableObjectFactory {
426         private final PoolableObjectFactory factory;
427 
428         KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory factory) throws IllegalArgumentException {
429             if (factory == null) {
430                 throw new IllegalArgumentException("factory must not be null.");
431             }
432             this.factory = factory;
433         }
434 
435         public Object makeObject(final Object key) throws Exception {
436             return factory.makeObject();
437         }
438 
439         public void destroyObject(final Object key, final Object obj) throws Exception {
440             factory.destroyObject(obj);
441         }
442 
443         public boolean validateObject(final Object key, final Object obj) {
444             return factory.validateObject(obj);
445         }
446 
447         public void activateObject(final Object key, final Object obj) throws Exception {
448             factory.activateObject(obj);
449         }
450 
451         public void passivateObject(final Object key, final Object obj) throws Exception {
452             factory.passivateObject(obj);
453         }
454 
455         public String toString() {
456             final StringBuffer sb = new StringBuffer();
457             sb.append("KeyedPoolableObjectFactoryAdaptor");
458             sb.append("{factory=").append(factory);
459             sb.append('}');
460             return sb.toString();
461         }
462     }
463 
464     private static class ObjectPoolAdaptor implements ObjectPool {
465         private final Object key;
466         private final KeyedObjectPool keyedPool;
467 
468         ObjectPoolAdaptor(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
469             if (keyedPool == null) {
470                 throw new IllegalArgumentException("keyedPool must not be null.");
471             }
472             if (key == null) {
473                 throw new IllegalArgumentException("key must not be null.");
474             }
475             this.keyedPool = keyedPool;
476             this.key = key;
477         }
478 
479         public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
480             return keyedPool.borrowObject(key);
481         }
482 
483         public void returnObject(final Object obj) throws Exception {
484             keyedPool.returnObject(key, obj);
485         }
486 
487         public void invalidateObject(final Object obj) throws Exception {
488             keyedPool.invalidateObject(key, obj);
489         }
490 
491         public void addObject() throws Exception, IllegalStateException {
492             keyedPool.addObject(key);
493         }
494 
495         public int getNumIdle() throws UnsupportedOperationException {
496             return keyedPool.getNumIdle(key);
497         }
498 
499         public int getNumActive() throws UnsupportedOperationException {
500             return keyedPool.getNumActive(key);
501         }
502 
503         public void clear() throws Exception, UnsupportedOperationException {
504             keyedPool.clear();
505         }
506 
507         public void close() throws Exception {
508             keyedPool.close();
509         }
510 
511         public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
512             keyedPool.setFactory(adapt(factory));
513         }
514 
515         public String toString() {
516             final StringBuffer sb = new StringBuffer();
517             sb.append("ObjectPoolAdaptor");
518             sb.append("{key=").append(key);
519             sb.append(", keyedPool=").append(keyedPool);
520             sb.append('}');
521             return sb.toString();
522         }
523     }
524 
525     private static class KeyedObjectPoolAdaptor implements KeyedObjectPool {
526         private final ObjectPool pool;
527 
528         KeyedObjectPoolAdaptor(final ObjectPool pool) throws IllegalArgumentException {
529             if (pool == null) {
530                 throw new IllegalArgumentException("keyedPool must not be null.");
531             }
532             this.pool = pool;
533         }
534 
535         public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
536             return pool.borrowObject();
537         }
538 
539         public void returnObject(final Object key, final Object obj) throws Exception {
540             pool.returnObject(obj);
541         }
542 
543         public void invalidateObject(final Object key, final Object obj) throws Exception {
544             pool.invalidateObject(obj);
545         }
546 
547         public void addObject(final Object key) throws Exception, IllegalStateException {
548             pool.addObject();
549         }
550 
551         public int getNumIdle(final Object key) throws UnsupportedOperationException {
552             return pool.getNumIdle();
553         }
554 
555         public int getNumActive(final Object key) throws UnsupportedOperationException {
556             return pool.getNumActive();
557         }
558 
559         public int getNumIdle() throws UnsupportedOperationException {
560             return pool.getNumIdle();
561         }
562 
563         public int getNumActive() throws UnsupportedOperationException {
564             return pool.getNumActive();
565         }
566 
567         public void clear() throws Exception, UnsupportedOperationException {
568             pool.clear();
569         }
570 
571         public void clear(final Object key) throws Exception, UnsupportedOperationException {
572             pool.clear();
573         }
574 
575         public void close() throws Exception {
576             pool.close();
577         }
578 
579         public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
580             pool.setFactory(adapt(factory));
581         }
582 
583         public String toString() {
584             final StringBuffer sb = new StringBuffer();
585             sb.append("KeyedObjectPoolAdaptor");
586             sb.append("{keyedPool=").append(pool);
587             sb.append('}');
588             return sb.toString();
589         }
590     }
591 
592     private static class CheckedObjectPool implements ObjectPool {
593         private final Class type;
594         private final ObjectPool pool;
595 
596         CheckedObjectPool(final ObjectPool pool, final Class type) {
597             if (pool == null) {
598                 throw new IllegalArgumentException("pool must not be null.");
599             }
600             if (type == null) {
601                 throw new IllegalArgumentException("type must not be null.");
602             }
603             this.pool = pool;
604             this.type = type;
605         }
606 
607         public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
608             final Object obj = pool.borrowObject();
609             if (type.isInstance(obj)) {
610                 return obj;
611             } else {
612                 throw new ClassCastException("Borrowed object is not of type: " + type.getName() + " was: " + obj);
613             }
614         }
615 
616         public void returnObject(final Object obj) throws Exception {
617             if (type.isInstance(obj)) {
618                 pool.returnObject(obj);
619             } else {
620                 throw new ClassCastException("Returned object is not of type: " + type.getName() + " was: " + obj);
621             }
622         }
623 
624         public void invalidateObject(final Object obj) throws Exception {
625             if (type.isInstance(obj)) {
626                 pool.invalidateObject(obj);
627             } else {
628                 throw new ClassCastException("Invalidated object is not of type: " + type.getName() + " was: " + obj);
629             }
630         }
631 
632         public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
633             pool.addObject();
634         }
635 
636         public int getNumIdle() throws UnsupportedOperationException {
637             return pool.getNumIdle();
638         }
639 
640         public int getNumActive() throws UnsupportedOperationException {
641             return pool.getNumActive();
642         }
643 
644         public void clear() throws Exception, UnsupportedOperationException {
645             pool.clear();
646         }
647 
648         public void close() throws Exception {
649             pool.close();
650         }
651 
652         public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
653             pool.setFactory(factory);
654         }
655 
656         public String toString() {
657             final StringBuffer sb = new StringBuffer();
658             sb.append("CheckedObjectPool");
659             sb.append("{type=").append(type);
660             sb.append(", keyedPool=").append(pool);
661             sb.append('}');
662             return sb.toString();
663         }
664     }
665 
666     private static class CheckedKeyedObjectPool implements KeyedObjectPool {
667         private final Class type;
668         private final KeyedObjectPool keyedPool;
669 
670         CheckedKeyedObjectPool(final KeyedObjectPool keyedPool, final Class type) {
671             if (keyedPool == null) {
672                 throw new IllegalArgumentException("keyedPool must not be null.");
673             }
674             if (type == null) {
675                 throw new IllegalArgumentException("type must not be null.");
676             }
677             this.keyedPool = keyedPool;
678             this.type = type;
679         }
680 
681         public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
682             Object obj = keyedPool.borrowObject(key);
683             if (type.isInstance(obj)) {
684                 return obj;
685             } else {
686                 throw new ClassCastException("Borrowed object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
687             }
688         }
689 
690         public void returnObject(final Object key, final Object obj) throws Exception {
691             if (type.isInstance(obj)) {
692                 keyedPool.returnObject(key, obj);
693             } else {
694                 throw new ClassCastException("Returned object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
695             }
696         }
697 
698         public void invalidateObject(final Object key, final Object obj) throws Exception {
699             if (type.isInstance(obj)) {
700                 keyedPool.invalidateObject(key, obj);
701             } else {
702                 throw new ClassCastException("Invalidated object for key: " + key + " is not of type: " + type.getName() + " was: " + obj);
703             }
704         }
705 
706         public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
707             keyedPool.addObject(key);
708         }
709 
710         public int getNumIdle(final Object key) throws UnsupportedOperationException {
711             return keyedPool.getNumIdle(key);
712         }
713 
714         public int getNumActive(final Object key) throws UnsupportedOperationException {
715             return keyedPool.getNumActive(key);
716         }
717 
718         public int getNumIdle() throws UnsupportedOperationException {
719             return keyedPool.getNumIdle();
720         }
721 
722         public int getNumActive() throws UnsupportedOperationException {
723             return keyedPool.getNumActive();
724         }
725 
726         public void clear() throws Exception, UnsupportedOperationException {
727             keyedPool.clear();
728         }
729 
730         public void clear(final Object key) throws Exception, UnsupportedOperationException {
731             keyedPool.clear(key);
732         }
733 
734         public void close() throws Exception {
735             keyedPool.close();
736         }
737 
738         public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
739             keyedPool.setFactory(factory);
740         }
741 
742         public String toString() {
743             final StringBuffer sb = new StringBuffer();
744             sb.append("CheckedKeyedObjectPool");
745             sb.append("{type=").append(type);
746             sb.append(", keyedPool=").append(keyedPool);
747             sb.append('}');
748             return sb.toString();
749         }
750     }
751 
752     private static class ObjectPoolMinIdleTimerTask extends TimerTask {
753         private final int minIdle;
754         private final ObjectPool pool;
755 
756         ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) throws IllegalArgumentException {
757             if (pool == null) {
758                 throw new IllegalArgumentException("poll must not be null.");
759             }
760             this.pool = pool;
761             this.minIdle = minIdle;
762         }
763 
764         public void run() {
765             boolean success = false;
766             try {
767                 if (pool.getNumIdle() < minIdle) {
768                     pool.addObject();
769                 }
770                 success = true;
771 
772             } catch (Exception e) {
773                 cancel();
774 
775             } finally {
776                 // detect other types of Throwable and cancel this Timer
777                 if (!success) {
778                     cancel();
779                 }
780             }
781         }
782 
783         public String toString() {
784             final StringBuffer sb = new StringBuffer();
785             sb.append("ObjectPoolMinIdleTimerTask");
786             sb.append("{minIdle=").append(minIdle);
787             sb.append(", keyedPool=").append(pool);
788             sb.append('}');
789             return sb.toString();
790         }
791     }
792 
793     private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask {
794         private final int minIdle;
795         private final Object key;
796         private final KeyedObjectPool pool;
797 
798         KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool pool, final Object key, final int minIdle) throws IllegalArgumentException {
799             if (pool == null) {
800                 throw new IllegalArgumentException("keyedPool must not be null.");
801             }
802             this.pool = pool;
803             this.key = key;
804             this.minIdle = minIdle;
805         }
806 
807         public void run() {
808             boolean success = false;
809             try {
810                 if (pool.getNumIdle(key) < minIdle) {
811                     pool.addObject(key);
812                 }
813                 success = true;
814 
815             } catch (Exception e) {
816                 cancel();
817 
818             } finally {
819                 // detect other types of Throwable and cancel this Timer
820                 if (!success) {
821                     cancel();
822                 }
823             }
824         }
825 
826         public String toString() {
827             final StringBuffer sb = new StringBuffer();
828             sb.append("KeyedObjectPoolMinIdleTimerTask");
829             sb.append("{minIdle=").append(minIdle);
830             sb.append(", key=").append(key);
831             sb.append(", keyedPool=").append(pool);
832             sb.append('}');
833             return sb.toString();
834         }
835     }
836 
837     private static class SynchronizedObjectPool implements ObjectPool {
838         private final Object lock;
839         private final ObjectPool pool;
840 
841         SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException {
842             if (pool == null) {
843                 throw new IllegalArgumentException("keyedPool must not be null.");
844             }
845             this.pool = pool;
846             lock = new Object();
847         }
848 
849         public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException {
850             synchronized (lock) {
851                 return pool.borrowObject();
852             }
853         }
854 
855         public void returnObject(final Object obj) throws Exception {
856             synchronized (lock) {
857                 pool.returnObject(obj);
858             }
859         }
860 
861         public void invalidateObject(final Object obj) throws Exception {
862             synchronized (lock) {
863                 pool.invalidateObject(obj);
864             }
865         }
866 
867         public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException {
868             synchronized (lock) {
869                 pool.addObject();
870             }
871         }
872 
873         public int getNumIdle() throws UnsupportedOperationException {
874             synchronized (lock) {
875                 return pool.getNumIdle();
876             }
877         }
878 
879         public int getNumActive() throws UnsupportedOperationException {
880             synchronized (lock) {
881                 return pool.getNumActive();
882             }
883         }
884 
885         public void clear() throws Exception, UnsupportedOperationException {
886             synchronized (lock) {
887                 pool.clear();
888             }
889         }
890 
891         public void close() throws Exception {
892             synchronized (lock) {
893                 pool.close();
894             }
895         }
896 
897         public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
898             synchronized (lock) {
899                 pool.setFactory(factory);
900             }
901         }
902 
903         public String toString() {
904             final StringBuffer sb = new StringBuffer();
905             sb.append("SynchronizedObjectPool");
906             sb.append("{keyedPool=").append(pool);
907             sb.append('}');
908             return sb.toString();
909         }
910     }
911 
912     private static class SynchronizedKeyedObjectPool implements KeyedObjectPool {
913         private final Object lock;
914         private final KeyedObjectPool keyedPool;
915 
916         SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
917             if (keyedPool == null) {
918                 throw new IllegalArgumentException("keyedPool must not be null.");
919             }
920             this.keyedPool = keyedPool;
921             lock = new Object();
922         }
923 
924         public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException {
925             synchronized (lock) {
926                 return keyedPool.borrowObject(key);
927             }
928         }
929 
930         public void returnObject(final Object key, final Object obj) throws Exception {
931             synchronized (lock) {
932                 keyedPool.returnObject(key, obj);
933             }
934         }
935 
936         public void invalidateObject(final Object key, final Object obj) throws Exception {
937             synchronized (lock) {
938                 keyedPool.invalidateObject(key, obj);
939             }
940         }
941 
942         public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException {
943             synchronized (lock) {
944                 keyedPool.addObject(key);
945             }
946         }
947 
948         public int getNumIdle(final Object key) throws UnsupportedOperationException {
949             synchronized (lock) {
950                 return keyedPool.getNumIdle(key);
951             }
952         }
953 
954         public int getNumActive(final Object key) throws UnsupportedOperationException {
955             synchronized (lock) {
956                 return keyedPool.getNumActive(key);
957             }
958         }
959 
960         public int getNumIdle() throws UnsupportedOperationException {
961             synchronized (lock) {
962                 return keyedPool.getNumIdle();
963             }
964         }
965 
966         public int getNumActive() throws UnsupportedOperationException {
967             synchronized (lock) {
968                 return keyedPool.getNumActive();
969             }
970         }
971 
972         public void clear() throws Exception, UnsupportedOperationException {
973             synchronized (lock) {
974                 keyedPool.clear();
975             }
976         }
977 
978         public void clear(final Object key) throws Exception, UnsupportedOperationException {
979             synchronized (lock) {
980                 keyedPool.clear(key);
981             }
982         }
983 
984         public void close() throws Exception {
985             synchronized (lock) {
986                 keyedPool.close();
987             }
988         }
989 
990         public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException {
991             synchronized (lock) {
992                 keyedPool.setFactory(factory);
993             }
994         }
995 
996         public String toString() {
997             final StringBuffer sb = new StringBuffer();
998             sb.append("SynchronizedKeyedObjectPool");
999             sb.append("{keyedPool=").append(keyedPool);
1000             sb.append('}');
1001             return sb.toString();
1002         }
1003     }
1004 
1005     private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory {
1006         private final Object lock;
1007         private final PoolableObjectFactory factory;
1008 
1009         SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException {
1010             if (factory == null) {
1011                 throw new IllegalArgumentException("factory must not be null.");
1012             }
1013             this.factory = factory;
1014             lock = new Object();
1015         }
1016 
1017         public Object makeObject() throws Exception {
1018             synchronized (lock) {
1019                 return factory.makeObject();
1020             }
1021         }
1022 
1023         public void destroyObject(final Object obj) throws Exception {
1024             synchronized (lock) {
1025                 factory.destroyObject(obj);
1026             }
1027         }
1028 
1029         public boolean validateObject(final Object obj) {
1030             synchronized (lock) {
1031                 return factory.validateObject(obj);
1032             }
1033         }
1034 
1035         public void activateObject(final Object obj) throws Exception {
1036             synchronized (lock) {
1037                 factory.activateObject(obj);
1038             }
1039         }
1040 
1041         public void passivateObject(final Object obj) throws Exception {
1042             synchronized (lock) {
1043                 factory.passivateObject(obj);
1044             }
1045         }
1046 
1047         public String toString() {
1048             final StringBuffer sb = new StringBuffer();
1049             sb.append("SynchronizedPoolableObjectFactory");
1050             sb.append("{factory=").append(factory);
1051             sb.append('}');
1052             return sb.toString();
1053         }
1054     }
1055 
1056     private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory {
1057         private final Object lock;
1058         private final KeyedPoolableObjectFactory keyedFactory;
1059 
1060         SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
1061             if (keyedFactory == null) {
1062                 throw new IllegalArgumentException("keyedFactory must not be null.");
1063             }
1064             this.keyedFactory = keyedFactory;
1065             lock = new Object();
1066         }
1067 
1068         public Object makeObject(final Object key) throws Exception {
1069             synchronized (lock) {
1070                 return keyedFactory.makeObject(key);
1071             }
1072         }
1073 
1074         public void destroyObject(final Object key, final Object obj) throws Exception {
1075             synchronized (lock) {
1076                 keyedFactory.destroyObject(key, obj);
1077             }
1078         }
1079 
1080         public boolean validateObject(final Object key, final Object obj) {
1081             synchronized (lock) {
1082                 return keyedFactory.validateObject(key, obj);
1083             }
1084         }
1085 
1086         public void activateObject(final Object key, final Object obj) throws Exception {
1087             synchronized (lock) {
1088                 keyedFactory.activateObject(key, obj);
1089             }
1090         }
1091 
1092         public void passivateObject(final Object key, final Object obj) throws Exception {
1093             synchronized (lock) {
1094                 keyedFactory.passivateObject(key, obj);
1095             }
1096         }
1097 
1098         public String toString() {
1099             final StringBuffer sb = new StringBuffer();
1100             sb.append("SynchronizedKeyedPoolableObjectFactory");
1101             sb.append("{keyedFactory=").append(keyedFactory);
1102             sb.append('}');
1103             return sb.toString();
1104         }
1105     }
1106 }