View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.pool;
19  
20  import java.lang.reflect.InvocationHandler;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Proxy;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.HashSet;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.TimerTask;
32  
33  import junit.framework.AssertionFailedError;
34  import junit.framework.TestCase;
35  
36  import org.apache.commons.pool.impl.GenericKeyedObjectPool;
37  import org.apache.commons.pool.impl.GenericObjectPool;
38  
39  /**
40   * Unit tests for {@link PoolUtils}.
41   *
42   * @author Sandy McArthur
43   * @version $Revision: 901944 $ $Date: 2010-01-21 17:27:04 -0700 (Thu, 21 Jan 2010) $
44   */
45  public class TestPoolUtils extends TestCase {
46  
47      /** Period between checks for minIdle tests. Increase this if you happen to get too many false failures. */
48      private static final int CHECK_PERIOD = 300;
49  
50      /** Times to let the minIdle check run. */
51      private static final int CHECK_COUNT = 4;
52  
53      /** Sleep time to let the minIdle tests run CHECK_COUNT times. */
54      private static final int CHECK_SLEEP_PERIOD = CHECK_PERIOD * (CHECK_COUNT - 1) + CHECK_PERIOD / 2;
55  
56      public void testJavaBeanInstantiation() {
57          new PoolUtils();
58      }
59  
60      public void testAdaptKeyedPoolableObjectFactory() throws Exception {
61          try {
62              PoolUtils.adapt((KeyedPoolableObjectFactory)null);
63              fail("PoolUtils.adapt(KeyedPoolableObjectFactory) must not allow null factory.");
64          } catch (IllegalArgumentException iae) {
65              // expected
66          }
67      }
68  
69      public void testAdaptKeyedPoolableObjectFactoryKey() throws Exception {
70          try {
71              PoolUtils.adapt((KeyedPoolableObjectFactory)null, new Object());
72              fail("PoolUtils.adapt(KeyedPoolableObjectFactory, key) must not allow null factory.");
73          } catch (IllegalArgumentException iae) {
74              // expected
75          }
76          try {
77              PoolUtils.adapt((KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFactory.class, (List)null), null);
78              fail("PoolUtils.adapt(KeyedPoolableObjectFactory, key) must not allow null key.");
79          } catch (IllegalArgumentException iae) {
80              // expected
81          }
82  
83          final List calledMethods = new ArrayList();
84          final KeyedPoolableObjectFactory kpof =
85                  (KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFactory.class, calledMethods);
86  
87          final PoolableObjectFactory pof = PoolUtils.adapt(kpof);
88          final List expectedMethods = invokeEveryMethod(pof);
89          assertEquals(expectedMethods, calledMethods);
90      }
91  
92      public void testAdaptPoolableObjectFactory() throws Exception {
93          try {
94              PoolUtils.adapt((PoolableObjectFactory)null);
95              fail("PoolUtils.adapt(PoolableObjectFactory) must not allow null factory.");
96          } catch (IllegalArgumentException iae) {
97              // expected
98          }
99  
100         final List calledMethods = new ArrayList();
101         final PoolableObjectFactory pof =
102                 (PoolableObjectFactory)createProxy(PoolableObjectFactory.class, calledMethods);
103 
104         final KeyedPoolableObjectFactory kpof = PoolUtils.adapt(pof);
105         final List expectedMethods = invokeEveryMethod(kpof);
106         assertEquals(expectedMethods, calledMethods);
107     }
108 
109     public void testAdaptKeyedObjectPool() throws Exception {
110         try {
111             PoolUtils.adapt((KeyedObjectPool)null);
112             fail("PoolUtils.adapt(KeyedObjectPool) must not allow a null pool.");
113         } catch(IllegalArgumentException iae) {
114             // expected
115         }
116     }
117 
118     public void testAdaptKeyedObjectPoolKey() throws Exception {
119         try {
120             PoolUtils.adapt((KeyedObjectPool)null, new Object());
121             fail("PoolUtils.adapt(KeyedObjectPool, key) must not allow a null pool.");
122         } catch(IllegalArgumentException iae) {
123             // expected
124         }
125         try {
126             PoolUtils.adapt((KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null), null);
127             fail("PoolUtils.adapt(KeyedObjectPool, key) must not allow a null key.");
128         } catch(IllegalArgumentException iae) {
129             // expected
130         }
131 
132         final List calledMethods = new ArrayList();
133         final KeyedObjectPool kop = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
134 
135         final ObjectPool op = PoolUtils.adapt(kop, new Object());
136         final List expectedMethods = invokeEveryMethod(op);
137         assertEquals(expectedMethods, calledMethods);
138     }
139 
140     public void testAdaptObjectPool() throws Exception {
141         try {
142             PoolUtils.adapt((ObjectPool)null);
143             fail("PoolUtils.adapt(ObjectPool) must not allow a null pool.");
144         } catch(IllegalArgumentException iae) {
145             // expected
146         }
147 
148         final List calledMethods = new ArrayList();
149         final ObjectPool op = (ObjectPool)createProxy(ObjectPool.class, calledMethods);
150 
151         final KeyedObjectPool kop = PoolUtils.adapt(op);
152         final List expectedMethods = invokeEveryMethod(kop);
153         assertEquals(expectedMethods, calledMethods);
154     }
155 
156     public void testCheckedPoolObjectPool() throws Exception {
157         try {
158             PoolUtils.checkedPool((ObjectPool)null, Object.class);
159             fail("PoolUtils.checkedPool(ObjectPool, Class) must not allow a null pool.");
160         } catch(IllegalArgumentException iae) {
161             // expected
162         }
163         try {
164             PoolUtils.checkedPool((ObjectPool)createProxy(ObjectPool.class, (List)null), null);
165             fail("PoolUtils.checkedPool(ObjectPool, Class) must not allow a null type.");
166         } catch(IllegalArgumentException iae) {
167             // expected
168         }
169 
170         final List calledMethods = new ArrayList();
171         ObjectPool op = (ObjectPool)createProxy(ObjectPool.class, calledMethods);
172 
173         ObjectPool cop = PoolUtils.checkedPool(op, Object.class);
174         final List expectedMethods = invokeEveryMethod(cop);
175         assertEquals(expectedMethods, calledMethods);
176 
177         op = new BaseObjectPool() {
178             public Object borrowObject() throws Exception {
179                 return new Integer(0);
180             }
181             public void returnObject(Object obj) {}
182             public void invalidateObject(Object obj) {}
183         };
184         cop = PoolUtils.checkedPool(op, String.class);
185 
186         try {
187             cop.borrowObject();
188             fail("borrowObject should have failed as Integer !instanceof String.");
189         } catch (ClassCastException cce) {
190             // expected
191         }
192         try {
193             cop.returnObject(new Integer(1));
194             fail("returnObject should have failed as Integer !instanceof String.");
195         } catch (ClassCastException cce) {
196             // expected
197         }
198         try {
199             cop.invalidateObject(new Integer(2));
200             fail("invalidateObject should have failed as Integer !instanceof String.");
201         } catch (ClassCastException cce) {
202             // expected
203         }
204     }
205 
206     public void testCheckedPoolKeyedObjectPool() throws Exception {
207         try {
208             PoolUtils.checkedPool((KeyedObjectPool)null, Object.class);
209             fail("PoolUtils.checkedPool(KeyedObjectPool, Class) must not allow a null pool.");
210         } catch(IllegalArgumentException iae) {
211             // expected
212         }
213         try {
214             PoolUtils.checkedPool((KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null), null);
215             fail("PoolUtils.checkedPool(KeyedObjectPool, Class) must not allow a null type.");
216         } catch(IllegalArgumentException iae) {
217             // expected
218         }
219 
220         final List calledMethods = new ArrayList();
221         KeyedObjectPool op = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
222 
223         KeyedObjectPool cop = PoolUtils.checkedPool(op, Object.class);
224         final List expectedMethods = invokeEveryMethod(cop);
225         assertEquals(expectedMethods, calledMethods);
226 
227 
228         op = new BaseKeyedObjectPool() {
229             public Object borrowObject(Object key) {
230                 return new Integer(0);
231             }
232 
233             public void returnObject(Object key, Object obj) {}
234 
235             public void invalidateObject(Object key, Object obj) {}
236         };
237         cop = PoolUtils.checkedPool(op, String.class);
238 
239         try {
240             cop.borrowObject(null);
241             fail("borrowObject should have failed as Integer !instanceof String.");
242         } catch (ClassCastException cce) {
243             // expected
244         }
245         try {
246             cop.returnObject(null, new Integer(1));
247             fail("returnObject should have failed as Integer !instanceof String.");
248         } catch (ClassCastException cce) {
249             // expected
250         }
251         try {
252             cop.invalidateObject(null, new Integer(2));
253             fail("invalidateObject should have failed as Integer !instanceof String.");
254         } catch (ClassCastException cce) {
255             // expected
256         }
257     }
258 
259     public void testCheckMinIdleObjectPool() throws Exception {
260         try {
261             PoolUtils.checkMinIdle(null, 1, 1);
262             fail("PoolUtils.checkMinIdle(ObjectPool,,) must not allow null pool.");
263         } catch (IllegalArgumentException iae) {
264             // expected
265         }
266         try {
267             final ObjectPool pool = (ObjectPool)createProxy(ObjectPool.class, (List)null);
268             PoolUtils.checkMinIdle(pool, -1, 1);
269             fail("PoolUtils.checkMinIdle(ObjectPool,,) must not accept negative min idle values.");
270         } catch (IllegalArgumentException iae) {
271             // expected
272         }
273 
274         final List calledMethods = new ArrayList();
275 
276         // Test that the minIdle check doesn't add too many idle objects
277         final PoolableObjectFactory pof = (PoolableObjectFactory)createProxy(PoolableObjectFactory.class, calledMethods);
278         final ObjectPool op = new GenericObjectPool(pof);
279         PoolUtils.checkMinIdle(op, 2, 100);
280         Thread.sleep(400);
281         assertEquals(2, op.getNumIdle());
282         op.close();
283         int makeObjectCount = 0;
284         final Iterator iter = calledMethods.iterator();
285         while (iter.hasNext()) {
286             final String methodName = (String)iter.next();
287             if ("makeObject".equals(methodName)) {
288                 makeObjectCount++;
289             }
290         }
291         assertEquals("makeObject should have been called two time", 2, makeObjectCount);
292 
293         // Because this isn't deterministic and you can get false failures, try more than once.
294         AssertionFailedError afe = null;
295         int triesLeft = 3;
296         do {
297             afe = null;
298             try {
299                 calledMethods.clear();
300                 final ObjectPool pool = (ObjectPool)createProxy(ObjectPool.class, calledMethods);
301                 final TimerTask task = PoolUtils.checkMinIdle(pool, 1, CHECK_PERIOD); // checks minIdle immediately
302 
303                 Thread.sleep(CHECK_SLEEP_PERIOD); // will check CHECK_COUNT more times.
304                 task.cancel();
305                 task.toString();
306 
307                 final List expectedMethods = new ArrayList();
308                 for (int i=0; i < CHECK_COUNT; i++) {
309                     expectedMethods.add("getNumIdle");
310                     expectedMethods.add("addObject");
311                 }
312                 expectedMethods.add("toString");
313                 assertEquals(expectedMethods, calledMethods); // may fail because of the thread scheduler
314             } catch (AssertionFailedError e) {
315                 afe = e;
316             }
317         } while (--triesLeft > 0 && afe != null);
318         if (afe != null) {
319             throw afe;
320         }
321     }
322 
323     public void testCheckMinIdleKeyedObjectPool() throws Exception {
324         try {
325             PoolUtils.checkMinIdle(null, new Object(), 1, 1);
326             fail("PoolUtils.checkMinIdle(KeyedObjectPool,Object,int,long) must not allow null pool.");
327         } catch (IllegalArgumentException iae) {
328             // expected
329         }
330         try {
331             final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null);
332             PoolUtils.checkMinIdle(pool, (Object)null, 1, 1);
333             fail("PoolUtils.checkMinIdle(KeyedObjectPool,Object,int,long) must not accept null keys.");
334         } catch (IllegalArgumentException iae) {
335             // expected
336         }
337         try {
338             final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null);
339             PoolUtils.checkMinIdle(pool, new Object(), -1, 1);
340             fail("PoolUtils.checkMinIdle(KeyedObjectPool,Object,int,long) must not accept negative min idle values.");
341         } catch (IllegalArgumentException iae) {
342             // expected
343         }
344 
345         final List calledMethods = new ArrayList();
346         final Object key = new Object();
347 
348         // Test that the minIdle check doesn't add too many idle objects
349         final KeyedPoolableObjectFactory kpof = (KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFactory.class, calledMethods);
350         final KeyedObjectPool kop = new GenericKeyedObjectPool(kpof);
351         PoolUtils.checkMinIdle(kop, key, 2, 100);
352         Thread.sleep(400);
353         assertEquals(2, kop.getNumIdle(key));
354         assertEquals(2, kop.getNumIdle());
355         kop.close();
356         int makeObjectCount = 0;
357         final Iterator iter = calledMethods.iterator();
358         while (iter.hasNext()) {
359             final String methodName = (String)iter.next();
360             if ("makeObject".equals(methodName)) {
361                 makeObjectCount++;
362             }
363         }
364         assertEquals("makeObject should have been called two time", 2, makeObjectCount);
365 
366         // Because this isn't deterministic and you can get false failures, try more than once.
367         AssertionFailedError afe = null;
368         int triesLeft = 3;
369         do {
370             afe = null;
371             try {
372                 calledMethods.clear();
373                 final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
374                 final TimerTask task = PoolUtils.checkMinIdle(pool, key, 1, CHECK_PERIOD); // checks minIdle immediately
375 
376                 Thread.sleep(CHECK_SLEEP_PERIOD); // will check CHECK_COUNT more times.
377                 task.cancel();
378                 task.toString();
379 
380                 final List expectedMethods = new ArrayList();
381                 for (int i=0; i < CHECK_COUNT; i++) {
382                     expectedMethods.add("getNumIdle");
383                     expectedMethods.add("addObject");
384                 }
385                 expectedMethods.add("toString");
386                 assertEquals(expectedMethods, calledMethods); // may fail because of the thread scheduler
387             } catch (AssertionFailedError e) {
388                 afe = e;
389             }
390         } while (--triesLeft > 0 && afe != null);
391         if (afe != null) {
392             throw afe;
393         }
394     }
395 
396     public void testCheckMinIdleKeyedObjectPoolKeys() throws Exception {
397         try {
398             final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null);
399             PoolUtils.checkMinIdle(pool, null, 1, 1);
400             fail("PoolUtils.checkMinIdle(KeyedObjectPool,Collection,int,long) must not accept null keys.");
401         } catch (IllegalArgumentException iae) {
402             // expected
403         }
404 
405         // Because this isn't determinist and you can get false failures, try more than once.
406         AssertionFailedError afe = null;
407         int triesLeft = 3;
408         do {
409             afe = null;
410             try {
411                 final List calledMethods = new ArrayList();
412                 final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
413                 final Collection keys = new ArrayList(2);
414                 keys.add("one");
415                 keys.add("two");
416                 final Map tasks = PoolUtils.checkMinIdle(pool, keys, 1, CHECK_PERIOD); // checks minIdle immediately
417 
418                 Thread.sleep(CHECK_SLEEP_PERIOD); // will check CHECK_COUNT more times.
419                 final Iterator iter = tasks.values().iterator();
420                 while (iter.hasNext()) {
421                     final TimerTask task = (TimerTask)iter.next();
422                     task.cancel();
423                 }
424 
425                 final List expectedMethods = new ArrayList();
426                 for (int i=0; i < CHECK_COUNT * keys.size(); i++) {
427                     expectedMethods.add("getNumIdle");
428                     expectedMethods.add("addObject");
429                 }
430                 assertEquals(expectedMethods, calledMethods); // may fail because of the thread scheduler
431             } catch (AssertionFailedError e) {
432                 afe = e;
433             }
434         } while (--triesLeft > 0 && afe != null);
435         if (afe != null) {
436             throw afe;
437         }
438     }
439 
440     public void testPrefillObjectPool() throws Exception {
441         try {
442             PoolUtils.prefill(null, 1);
443             fail("PoolUtils.prefill(ObjectPool,int) must not allow null pool.");
444         } catch (IllegalArgumentException iae) {
445             // expected
446         }
447 
448         final List calledMethods = new ArrayList();
449         final ObjectPool pool = (ObjectPool)createProxy(ObjectPool.class, calledMethods);
450 
451         PoolUtils.prefill(pool, 0);
452         final List expectedMethods = new ArrayList();
453         assertEquals(expectedMethods, calledMethods);
454 
455         calledMethods.clear();
456         PoolUtils.prefill(pool, 3);
457         for (int i=0; i < 3; i++) {
458             expectedMethods.add("addObject");
459         }
460         assertEquals(expectedMethods, calledMethods);
461     }
462 
463     public void testPrefillKeyedObjectPool() throws Exception {
464         try {
465             PoolUtils.prefill(null, new Object(), 1);
466             fail("PoolUtils.prefill(KeyedObjectPool,Object,int) must not accept null pool.");
467         } catch (IllegalArgumentException iae) {
468             // expected
469         }
470         try {
471             final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null);
472             PoolUtils.prefill(pool, (Object)null, 1);
473             fail("PoolUtils.prefill(KeyedObjectPool,Object,int) must not accept null key.");
474         } catch (IllegalArgumentException iae) {
475             // expected
476         }
477 
478         final List calledMethods = new ArrayList();
479         final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
480 
481         PoolUtils.prefill(pool, new Object(), 0);
482         final List expectedMethods = new ArrayList();
483         assertEquals(expectedMethods, calledMethods);
484 
485         calledMethods.clear();
486         PoolUtils.prefill(pool, new Object(), 3);
487         for (int i=0; i < 3; i++) {
488             expectedMethods.add("addObject");
489         }
490         assertEquals(expectedMethods, calledMethods);
491     }
492 
493     public void testPrefillKeyedObjectPoolCollection() throws Exception {
494         try {
495             final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, (List)null);
496             PoolUtils.prefill(pool, null, 1);
497             fail("PoolUtils.prefill(KeyedObjectPool,Collection,int) must not accept null keys.");
498         } catch (IllegalArgumentException iae) {
499             // expected
500         }
501 
502         final List calledMethods = new ArrayList();
503         final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
504 
505         final Set keys = new HashSet();
506         PoolUtils.prefill(pool, keys, 0);
507         final List expectedMethods = new ArrayList();
508         assertEquals(expectedMethods, calledMethods);
509 
510         calledMethods.clear();
511         keys.add(new Integer(1));
512         keys.add("two");
513         keys.add(new Double(3.1415926));
514         PoolUtils.prefill(pool, keys, 3);
515         for (int i=0; i < keys.size() * 3; i++) {
516             expectedMethods.add("addObject");
517         }
518         assertEquals(expectedMethods, calledMethods);
519     }
520 
521     public void testSynchronizedPoolObjectPool() throws Exception {
522         try {
523             PoolUtils.synchronizedPool((ObjectPool)null);
524             fail("PoolUtils.synchronizedPool(ObjectPool) must not allow a null pool.");
525         } catch(IllegalArgumentException iae) {
526             // expected
527         }
528 
529         final List calledMethods = new ArrayList();
530         final ObjectPool op = (ObjectPool)createProxy(ObjectPool.class, calledMethods);
531 
532         final ObjectPool sop = PoolUtils.synchronizedPool(op);
533         final List expectedMethods = invokeEveryMethod(sop);
534         assertEquals(expectedMethods, calledMethods);
535 
536         // TODO: Anyone feel motivated to construct a test that verifies proper synchronization?
537     }
538 
539     public void testSynchronizedPoolKeyedObjectPool() throws Exception {
540         try {
541             PoolUtils.synchronizedPool((KeyedObjectPool)null);
542             fail("PoolUtils.synchronizedPool(KeyedObjectPool) must not allow a null pool.");
543         } catch(IllegalArgumentException iae) {
544             // expected
545         }
546 
547         final List calledMethods = new ArrayList();
548         final KeyedObjectPool kop = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods);
549 
550         final KeyedObjectPool skop = PoolUtils.synchronizedPool(kop);
551         final List expectedMethods = invokeEveryMethod(skop);
552         assertEquals(expectedMethods, calledMethods);
553 
554         // TODO: Anyone feel motivated to construct a test that verifies proper synchronization?
555     }
556 
557     public void testSynchronizedPoolableFactoryPoolableObjectFactory() throws Exception {
558         try {
559             PoolUtils.synchronizedPoolableFactory((PoolableObjectFactory)null);
560             fail("PoolUtils.synchronizedPoolableFactory(PoolableObjectFactory) must not allow a null factory.");
561         } catch(IllegalArgumentException iae) {
562             // expected
563         }
564 
565         final List calledMethods = new ArrayList();
566         final PoolableObjectFactory pof =
567                 (PoolableObjectFactory)createProxy(PoolableObjectFactory.class, calledMethods);
568 
569         final PoolableObjectFactory spof = PoolUtils.synchronizedPoolableFactory(pof);
570         final List expectedMethods = invokeEveryMethod(spof);
571         assertEquals(expectedMethods, calledMethods);
572 
573         // TODO: Anyone feel motivated to construct a test that verifies proper synchronization?
574     }
575 
576     public void testSynchronizedPoolableFactoryKeyedPoolableObjectFactory() throws Exception {
577         try {
578             PoolUtils.synchronizedPoolableFactory((KeyedPoolableObjectFactory)null);
579             fail("PoolUtils.synchronizedPoolableFactory(KeyedPoolableObjectFactory) must not allow a null factory.");
580         } catch(IllegalArgumentException iae) {
581             // expected
582         }
583 
584         final List calledMethods = new ArrayList();
585         final KeyedPoolableObjectFactory kpof =
586                 (KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFactory.class, calledMethods);
587 
588         final KeyedPoolableObjectFactory skpof = PoolUtils.synchronizedPoolableFactory(kpof);
589         final List expectedMethods = invokeEveryMethod(skpof);
590         assertEquals(expectedMethods, calledMethods);
591 
592         // TODO: Anyone feel motivated to construct a test that verifies proper synchronization?
593     }
594 
595     public void testErodingPoolObjectPool() throws Exception {
596         try {
597             PoolUtils.erodingPool((ObjectPool)null);
598             fail("PoolUtils.erodingPool(ObjectPool) must not allow a null pool.");
599         } catch(IllegalArgumentException iae) {
600             // expected
601         }
602 
603         try {
604             PoolUtils.erodingPool((ObjectPool)null, 1f);
605             fail("PoolUtils.erodingPool(ObjectPool, float) must not allow a null pool.");
606         } catch(IllegalArgumentException iae) {
607             // expected
608         }
609 
610         try {
611             PoolUtils.erodingPool((ObjectPool)null, 0);
612             fail("PoolUtils.erodingPool(ObjectPool, float) must not allow a non-positive factor.");
613         } catch(IllegalArgumentException iae) {
614             // expected
615         }
616 
617         final List calledMethods = new ArrayList();
618         final InvocationHandler handler = new MethodCallLogger(calledMethods) {
619             public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
620                 Object o = super.invoke(proxy, method, args);
621                 if (o instanceof Integer) {
622                     // so getNumActive/getNumIdle are not zero.
623                     o = new Integer(1);
624                 }
625                 return o;
626             }
627         };
628 
629         // If the logic behind PoolUtils.erodingPool changes then this will need to be tweaked.
630         float factor = 0.01f; // about ~9 seconds until first discard
631         final ObjectPool pool = PoolUtils.erodingPool((ObjectPool)createProxy(ObjectPool.class, handler), factor);
632 
633         final List expectedMethods = new ArrayList();
634         assertEquals(expectedMethods, calledMethods);
635 
636         Object o = pool.borrowObject();
637         expectedMethods.add("borrowObject");
638 
639         assertEquals(expectedMethods, calledMethods);
640 
641         pool.returnObject(o);
642         expectedMethods.add("returnObject");
643         assertEquals(expectedMethods, calledMethods);
644 
645         for (int i=0; i < 5; i ++) {
646             o = pool.borrowObject();
647             expectedMethods.add("borrowObject");
648 
649             Thread.sleep(50);
650 
651             pool.returnObject(o);
652             expectedMethods.add("returnObject");
653 
654             assertEquals(expectedMethods, calledMethods);
655 
656             expectedMethods.clear();
657             calledMethods.clear();
658         }
659 
660         Thread.sleep(10000); // 10 seconds
661 
662         
663         o = pool.borrowObject();
664         expectedMethods.add("borrowObject");
665         pool.returnObject(o);
666         expectedMethods.add("getNumIdle");
667         expectedMethods.add("invalidateObject");
668         assertEquals(expectedMethods, calledMethods);
669     }
670 
671     public void testErodingPoolKeyedObjectPool() throws Exception {
672         try {
673             PoolUtils.erodingPool((KeyedObjectPool)null);
674             fail("PoolUtils.erodingPool(KeyedObjectPool) must not allow a null pool.");
675         } catch(IllegalArgumentException iae) {
676             // expected
677         }
678 
679         try {
680             PoolUtils.erodingPool((KeyedObjectPool)null, 1f);
681             fail("PoolUtils.erodingPool(KeyedObjectPool, float) must not allow a null pool.");
682         } catch(IllegalArgumentException iae) {
683             // expected
684         }
685 
686         try {
687             PoolUtils.erodingPool((KeyedObjectPool)null, 0);
688             fail("PoolUtils.erodingPool(ObjectPool, float) must not allow a non-positive factor.");
689         } catch(IllegalArgumentException iae) {
690             // expected
691         }
692 
693         try {
694             PoolUtils.erodingPool((KeyedObjectPool)null, 1f, true);
695             fail("PoolUtils.erodingPool(KeyedObjectPool, float, boolean) must not allow a null pool.");
696         } catch(IllegalArgumentException iae) {
697             // expected
698         }
699 
700         try {
701             PoolUtils.erodingPool((KeyedObjectPool)null, 0, false);
702             fail("PoolUtils.erodingPool(ObjectPool, float, boolean) must not allow a non-positive factor.");
703         } catch(IllegalArgumentException iae) {
704             // expected
705         }
706 
707         final List calledMethods = new ArrayList();
708         final InvocationHandler handler = new MethodCallLogger(calledMethods) {
709             public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
710                 Object o = super.invoke(proxy, method, args);
711                 if (o instanceof Integer) {
712                     // so getNumActive/getNumIdle are not zero.
713                     o = new Integer(1);
714                 }
715                 return o;
716             }
717         };
718 
719         // If the logic behind PoolUtils.erodingPool changes then this will need to be tweaked.
720         float factor = 0.01f; // about ~9 seconds until first discard
721         final KeyedObjectPool pool = PoolUtils.erodingPool((KeyedObjectPool)createProxy(KeyedObjectPool.class, handler), factor);
722 
723         final List expectedMethods = new ArrayList();
724         assertEquals(expectedMethods, calledMethods);
725 
726         final Object key = "key";
727 
728         Object o = pool.borrowObject(key);
729         expectedMethods.add("borrowObject");
730 
731         assertEquals(expectedMethods, calledMethods);
732 
733         pool.returnObject(key, o);
734         expectedMethods.add("returnObject");
735         assertEquals(expectedMethods, calledMethods);
736 
737         for (int i=0; i < 5; i ++) {
738             o = pool.borrowObject(key);
739             expectedMethods.add("borrowObject");
740 
741             Thread.sleep(50);
742 
743             pool.returnObject(key, o);
744             expectedMethods.add("returnObject");
745 
746             assertEquals(expectedMethods, calledMethods);
747 
748             expectedMethods.clear();
749             calledMethods.clear();
750         }
751 
752         Thread.sleep(10000); // 10 seconds
753 
754 
755         o = pool.borrowObject(key);
756         expectedMethods.add("borrowObject");
757         pool.returnObject(key, o);
758         expectedMethods.add("getNumIdle");
759         expectedMethods.add("invalidateObject");
760         assertEquals(expectedMethods, calledMethods);
761     }
762     
763     public void testErodingPerKeyKeyedObjectPool() throws Exception {
764         try {
765             PoolUtils.erodingPool((KeyedObjectPool)null, 1, true);
766             fail("PoolUtils.erodingPool(KeyedObjectPool) must not allow a null pool.");
767         } catch(IllegalArgumentException iae) {
768             // expected
769         }
770 
771         try {
772             PoolUtils.erodingPool((KeyedObjectPool)null, 0, true);
773             fail("PoolUtils.erodingPool(ObjectPool, float) must not allow a non-positive factor.");
774         } catch(IllegalArgumentException iae) {
775             // expected
776         }
777 
778         try {
779             PoolUtils.erodingPool((KeyedObjectPool)null, 1f, true);
780             fail("PoolUtils.erodingPool(KeyedObjectPool, float, boolean) must not allow a null pool.");
781         } catch(IllegalArgumentException iae) {
782             // expected
783         }
784 
785         final List calledMethods = new ArrayList();
786         final InvocationHandler handler = new MethodCallLogger(calledMethods) {
787             public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
788                 Object o = super.invoke(proxy, method, args);
789                 if (o instanceof Integer) {
790                     // so getNumActive/getNumIdle are not zero.
791                     o = new Integer(1);
792                 }
793                 return o;
794             }
795         };
796 
797         // If the logic behind PoolUtils.erodingPool changes then this will need to be tweaked.
798         float factor = 0.01f; // about ~9 seconds until first discard
799         final KeyedObjectPool pool = PoolUtils.erodingPool((KeyedObjectPool)createProxy(KeyedObjectPool.class, handler), factor, true);
800 
801         final List expectedMethods = new ArrayList();
802         assertEquals(expectedMethods, calledMethods);
803 
804         final Object key = "key";
805 
806         Object o = pool.borrowObject(key);
807         expectedMethods.add("borrowObject");
808 
809         assertEquals(expectedMethods, calledMethods);
810 
811         pool.returnObject(key, o);
812         expectedMethods.add("returnObject");
813         assertEquals(expectedMethods, calledMethods);
814 
815         for (int i=0; i < 5; i ++) {
816             o = pool.borrowObject(key);
817             expectedMethods.add("borrowObject");
818 
819             Thread.sleep(50);
820 
821             pool.returnObject(key, o);
822             expectedMethods.add("returnObject");
823 
824             assertEquals(expectedMethods, calledMethods);
825 
826             expectedMethods.clear();
827             calledMethods.clear();
828         }
829 
830         Thread.sleep(10000); // 10 seconds
831 
832 
833         o = pool.borrowObject(key);
834         expectedMethods.add("borrowObject");
835         pool.returnObject(key, o);
836         expectedMethods.add("getNumIdle");
837         expectedMethods.add("invalidateObject");
838         assertEquals(expectedMethods, calledMethods);
839     }
840 
841     private static List invokeEveryMethod(ObjectPool op) throws Exception {
842         op.addObject();
843         op.borrowObject();
844         op.clear();
845         op.close();
846         op.getNumActive();
847         op.getNumIdle();
848         op.invalidateObject(new Object());
849         op.returnObject(new Object());
850         op.setFactory((PoolableObjectFactory)createProxy(PoolableObjectFactory.class, (List)null));
851         op.toString();
852 
853         final List expectedMethods = Arrays.asList(new String[] {
854                 "addObject", "borrowObject", "clear", "close",
855                 "getNumActive", "getNumIdle", "invalidateObject",
856                 "returnObject", "setFactory", "toString"
857         });
858         return expectedMethods;
859     }
860 
861     private static List invokeEveryMethod(KeyedObjectPool kop) throws Exception {
862         kop.addObject(null);
863         kop.borrowObject(null);
864         kop.clear();
865         kop.clear(null);
866         kop.close();
867         kop.getNumActive();
868         kop.getNumActive(null);
869         kop.getNumIdle();
870         kop.getNumIdle(null);
871         kop.invalidateObject(null, new Object());
872         kop.returnObject(null, new Object());
873         kop.setFactory((KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFactory.class, (List)null));
874         kop.toString();
875 
876         final List expectedMethods = Arrays.asList(new String[] {
877                 "addObject", "borrowObject", "clear", "clear", "close",
878                 "getNumActive", "getNumActive", "getNumIdle", "getNumIdle", "invalidateObject",
879                 "returnObject", "setFactory", "toString"
880         });
881         return expectedMethods;
882     }
883 
884     private static List invokeEveryMethod(PoolableObjectFactory pof) throws Exception {
885         pof.activateObject(null);
886         pof.destroyObject(null);
887         pof.makeObject();
888         pof.passivateObject(null);
889         pof.validateObject(null);
890         pof.toString();
891 
892         final List expectedMethods = Arrays.asList(new String[] {
893                 "activateObject", "destroyObject", "makeObject",
894                 "passivateObject", "validateObject", "toString",
895         });
896         return expectedMethods;
897     }
898 
899     private static List invokeEveryMethod(KeyedPoolableObjectFactory kpof) throws Exception {
900         kpof.activateObject(null, null);
901         kpof.destroyObject(null, null);
902         kpof.makeObject(null);
903         kpof.passivateObject(null, null);
904         kpof.validateObject(null, null);
905         kpof.toString();
906 
907         final List expectedMethods = Arrays.asList(new String[] {
908                 "activateObject", "destroyObject", "makeObject",
909                 "passivateObject", "validateObject", "toString",
910         });
911         return expectedMethods;
912     }
913 
914     private static Object createProxy(final Class clazz, final List logger) {
915         return createProxy(clazz, new MethodCallLogger(logger));
916     }
917 
918     private static Object createProxy(final Class clazz, final InvocationHandler handler) {
919         return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, handler);
920     }
921 
922     private static class MethodCallLogger implements InvocationHandler {
923         private final List calledMethods;
924 
925         MethodCallLogger(final List calledMethods) {
926             this.calledMethods = calledMethods;
927         }
928 
929         public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
930             calledMethods.add(method.getName());
931             if (boolean.class.equals(method.getReturnType())) {
932                 return Boolean.FALSE;
933             } else if (int.class.equals(method.getReturnType())) {
934                 return new Integer(0);
935             } else if (long.class.equals(method.getReturnType())) {
936                 return new Long(0);
937             } else if (Object.class.equals(method.getReturnType())) {
938                 return new Object();
939             } else {
940                 return null;
941             }
942         }
943     }
944 }