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.impl;
19  
20  import junit.framework.Test;
21  import junit.framework.TestSuite;
22  import org.apache.commons.pool.KeyedObjectPool;
23  import org.apache.commons.pool.KeyedPoolableObjectFactory;
24  import org.apache.commons.pool.TestBaseKeyedObjectPool;
25  import org.apache.commons.pool.VisitTracker;
26  import org.apache.commons.pool.VisitTrackerFactory;
27  
28  import java.util.HashMap;
29  import java.util.NoSuchElementException;
30  import java.util.Random;
31  
32  /***
33   * @author Rodney Waldhoff
34   * @version $Revision: 606718 $ $Date: 2007-12-24 10:55:10 -0700 (Mon, 24 Dec 2007) $
35   */
36  public class TestGenericKeyedObjectPool extends TestBaseKeyedObjectPool {
37      public TestGenericKeyedObjectPool(String testName) {
38          super(testName);
39      }
40  
41      public static Test suite() {
42          return new TestSuite(TestGenericKeyedObjectPool.class);
43      }
44  
45      protected KeyedObjectPool makeEmptyPool(int mincapacity) {
46          GenericKeyedObjectPool pool = new GenericKeyedObjectPool(
47              new KeyedPoolableObjectFactory()  {
48                  HashMap map = new HashMap();
49                  public Object makeObject(Object key) {
50                      int counter = 0;
51                      Integer Counter = (Integer)(map.get(key));
52                      if(null != Counter) {
53                          counter = Counter.intValue();
54                      }
55                      map.put(key,new Integer(counter + 1));
56                      return String.valueOf(key) + String.valueOf(counter);
57                  }
58                  public void destroyObject(Object key, Object obj) { }
59                  public boolean validateObject(Object key, Object obj) { return true; }
60                  public void activateObject(Object key, Object obj) { }
61                  public void passivateObject(Object key, Object obj) { }
62              }
63          );
64          pool.setMaxActive(mincapacity);
65          pool.setMaxIdle(mincapacity);
66          return pool;
67      }
68  
69      protected KeyedObjectPool makeEmptyPool(KeyedPoolableObjectFactory factory) {
70          return new GenericKeyedObjectPool(factory);
71      }
72  
73      protected Object getNthObject(Object key, int n) {
74          return String.valueOf(key) + String.valueOf(n);
75      }
76  
77      protected Object makeKey(int n) {
78          return String.valueOf(n);
79      }
80  
81      private GenericKeyedObjectPool pool = null;
82      private Integer zero = new Integer(0);
83      private Integer one = new Integer(1);
84      private Integer two = new Integer(2);
85  
86      public void setUp() throws Exception {
87          super.setUp();
88          pool = new GenericKeyedObjectPool(new SimpleFactory());
89      }
90  
91      public void tearDown() throws Exception {
92          super.tearDown();
93          pool.close();
94          pool = null;
95      }
96  
97      public void testNegativeMaxActive() throws Exception {
98          pool.setMaxActive(-1);
99          pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
100         Object obj = pool.borrowObject("");
101         assertEquals("0",obj);
102         pool.returnObject("",obj);
103     }
104 
105     public void testNumActiveNumIdle2() throws Exception {
106         assertEquals(0,pool.getNumActive());
107         assertEquals(0,pool.getNumIdle());
108         assertEquals(0,pool.getNumActive("A"));
109         assertEquals(0,pool.getNumIdle("A"));
110         assertEquals(0,pool.getNumActive("B"));
111         assertEquals(0,pool.getNumIdle("B"));
112 
113         Object objA0 = pool.borrowObject("A");
114         Object objB0 = pool.borrowObject("B");
115 
116         assertEquals(2,pool.getNumActive());
117         assertEquals(0,pool.getNumIdle());
118         assertEquals(1,pool.getNumActive("A"));
119         assertEquals(0,pool.getNumIdle("A"));
120         assertEquals(1,pool.getNumActive("B"));
121         assertEquals(0,pool.getNumIdle("B"));
122 
123         Object objA1 = pool.borrowObject("A");
124         Object objB1 = pool.borrowObject("B");
125 
126         assertEquals(4,pool.getNumActive());
127         assertEquals(0,pool.getNumIdle());
128         assertEquals(2,pool.getNumActive("A"));
129         assertEquals(0,pool.getNumIdle("A"));
130         assertEquals(2,pool.getNumActive("B"));
131         assertEquals(0,pool.getNumIdle("B"));
132 
133         pool.returnObject("A",objA0);
134         pool.returnObject("B",objB0);
135 
136         assertEquals(2,pool.getNumActive());
137         assertEquals(2,pool.getNumIdle());
138         assertEquals(1,pool.getNumActive("A"));
139         assertEquals(1,pool.getNumIdle("A"));
140         assertEquals(1,pool.getNumActive("B"));
141         assertEquals(1,pool.getNumIdle("B"));
142 
143         pool.returnObject("A",objA1);
144         pool.returnObject("B",objB1);
145 
146         assertEquals(0,pool.getNumActive());
147         assertEquals(4,pool.getNumIdle());
148         assertEquals(0,pool.getNumActive("A"));
149         assertEquals(2,pool.getNumIdle("A"));
150         assertEquals(0,pool.getNumActive("B"));
151         assertEquals(2,pool.getNumIdle("B"));
152     }
153 
154     public void testMaxIdle() throws Exception {
155         pool.setMaxActive(100);
156         pool.setMaxIdle(8);
157         Object[] active = new Object[100];
158         for(int i=0;i<100;i++) {
159             active[i] = pool.borrowObject("");
160         }
161         assertEquals(100,pool.getNumActive(""));
162         assertEquals(0,pool.getNumIdle(""));
163         for(int i=0;i<100;i++) {
164             pool.returnObject("",active[i]);
165             assertEquals(99 - i,pool.getNumActive(""));
166             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle(""));
167         }
168         
169         for(int i=0;i<100;i++) {
170             active[i] = pool.borrowObject("a");
171         }
172         assertEquals(100,pool.getNumActive("a"));
173         assertEquals(0,pool.getNumIdle("a"));
174         for(int i=0;i<100;i++) {
175             pool.returnObject("a",active[i]);
176             assertEquals(99 - i,pool.getNumActive("a"));
177             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle("a"));
178         }
179         
180         // total number of idle instances is twice maxIdle
181         assertEquals(16, pool.getNumIdle());
182         // Each pool is at the sup
183         assertEquals(8, pool.getNumIdle(""));
184         assertEquals(8, pool.getNumIdle("a"));
185              
186     }
187 
188     public void testMaxActive() throws Exception {
189         pool.setMaxActive(3);
190         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
191 
192         pool.borrowObject("");
193         pool.borrowObject("");
194         pool.borrowObject("");
195         try {
196             pool.borrowObject("");
197             fail("Expected NoSuchElementException");
198         } catch(NoSuchElementException e) {
199             // expected
200         }
201     }
202 
203     public void testMaxActiveZero() throws Exception {
204         pool.setMaxActive(0);
205         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
206 
207         try {
208             pool.borrowObject("a");
209             fail("Expected NoSuchElementException");
210         } catch(NoSuchElementException e) {
211             // expected
212         }
213     }
214 
215     public void testMaxTotal() throws Exception {
216         pool.setMaxActive(2);
217         pool.setMaxTotal(3);
218         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
219 
220         Object o1 = pool.borrowObject("a");
221         assertNotNull(o1);
222         Object o2 = pool.borrowObject("a");
223         assertNotNull(o2);
224         Object o3 = pool.borrowObject("b");
225         assertNotNull(o3);
226         try {
227             pool.borrowObject("c");
228             fail("Expected NoSuchElementException");
229         } catch(NoSuchElementException e) {
230             // expected
231         }
232 
233         assertEquals(0, pool.getNumIdle());
234 
235         pool.returnObject("b", o3);
236         assertEquals(1, pool.getNumIdle());
237         assertEquals(1, pool.getNumIdle("b"));
238 
239         Object o4 = pool.borrowObject("b");
240         assertNotNull(o4);
241         assertEquals(0, pool.getNumIdle());
242         assertEquals(0, pool.getNumIdle("b"));
243         
244         pool.setMaxTotal(4);
245         Object o5 = pool.borrowObject("b");
246         assertNotNull(o5);
247         
248         assertEquals(2, pool.getNumActive("a"));
249         assertEquals(2, pool.getNumActive("b"));
250         assertEquals(pool.getMaxTotal(),
251                 pool.getNumActive("b") + pool.getNumActive("b"));
252         assertEquals(pool.getNumActive(),
253                 pool.getMaxTotal());
254     }
255 
256     public void testMaxTotalZero() throws Exception {
257         pool.setMaxTotal(0);
258         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
259 
260         try {
261             pool.borrowObject("a");
262             fail("Expected NoSuchElementException");
263         } catch(NoSuchElementException e) {
264             // expected
265         }
266     }
267 
268     public void testMaxTotalLRU() throws Exception {
269         pool.setMaxActive(2);
270         pool.setMaxTotal(3);
271 //        pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW);
272 
273         Object o1 = pool.borrowObject("a");
274         assertNotNull(o1);
275         pool.returnObject("a", o1);
276         Thread.sleep(25);
277 
278         Object o2 = pool.borrowObject("b");
279         assertNotNull(o2);
280         pool.returnObject("b", o2);
281         Thread.sleep(25);
282 
283         Object o3 = pool.borrowObject("c");
284         assertNotNull(o3);
285         pool.returnObject("c", o3);
286         Thread.sleep(25);
287 
288         Object o4 = pool.borrowObject("a");
289         assertNotNull(o4);
290         pool.returnObject("a", o4);
291         Thread.sleep(25);
292 
293         assertSame(o1, o4);
294 
295         // this should cause b to be bumped out of the pool
296         Object o5 = pool.borrowObject("d");
297         assertNotNull(o5);
298         pool.returnObject("d", o5);
299         Thread.sleep(25);
300 
301         // now re-request b, we should get a different object because it should
302         // have been expelled from pool (was oldest because a was requested after b)
303         Object o6 = pool.borrowObject("b");
304         assertNotNull(o6);
305         pool.returnObject("b", o6);
306 
307         assertNotSame(o1, o6);
308 
309         // second a is still in there
310         Object o7 = pool.borrowObject("a");
311         assertNotNull(o7);
312         pool.returnObject("a", o7);
313 
314         assertSame(o4, o7);
315     }
316 
317     public void testSettersAndGetters() throws Exception {
318         GenericKeyedObjectPool pool = new GenericKeyedObjectPool();
319         {
320             pool.setFactory(new SimpleFactory());
321         }
322         {
323             pool.setMaxActive(123);
324             assertEquals(123,pool.getMaxActive());
325         }
326         {
327             pool.setMaxIdle(12);
328             assertEquals(12,pool.getMaxIdle());
329         }
330         {
331             pool.setMaxWait(1234L);
332             assertEquals(1234L,pool.getMaxWait());
333         }
334         {
335             pool.setMinEvictableIdleTimeMillis(12345L);
336             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
337         }
338         {
339             pool.setNumTestsPerEvictionRun(11);
340             assertEquals(11,pool.getNumTestsPerEvictionRun());
341         }
342         {
343             pool.setTestOnBorrow(true);
344             assertTrue(pool.getTestOnBorrow());
345             pool.setTestOnBorrow(false);
346             assertTrue(!pool.getTestOnBorrow());
347         }
348         {
349             pool.setTestOnReturn(true);
350             assertTrue(pool.getTestOnReturn());
351             pool.setTestOnReturn(false);
352             assertTrue(!pool.getTestOnReturn());
353         }
354         {
355             pool.setTestWhileIdle(true);
356             assertTrue(pool.getTestWhileIdle());
357             pool.setTestWhileIdle(false);
358             assertTrue(!pool.getTestWhileIdle());
359         }
360         {
361             pool.setTimeBetweenEvictionRunsMillis(11235L);
362             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
363         }
364         {
365             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK);
366             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK,pool.getWhenExhaustedAction());
367             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
368             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_FAIL,pool.getWhenExhaustedAction());
369             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW);
370             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_GROW,pool.getWhenExhaustedAction());
371         }
372     }
373 
374     public void testEviction() throws Exception {
375         pool.setMaxIdle(500);
376         pool.setMaxActive(500);
377         pool.setNumTestsPerEvictionRun(100);
378         pool.setMinEvictableIdleTimeMillis(250L);
379         pool.setTimeBetweenEvictionRunsMillis(500L);
380 
381         Object[] active = new Object[500];
382         for(int i=0;i<500;i++) {
383             active[i] = pool.borrowObject("");
384         }
385         for(int i=0;i<500;i++) {
386             pool.returnObject("",active[i]);
387         }
388 
389         try { Thread.sleep(1000L); } catch(Exception e) { }
390         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 500);
391         try { Thread.sleep(600L); } catch(Exception e) { }
392         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 400);
393         try { Thread.sleep(600L); } catch(Exception e) { }
394         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 300);
395         try { Thread.sleep(600L); } catch(Exception e) { }
396         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 200);
397         try { Thread.sleep(600L); } catch(Exception e) { }
398         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 100);
399         try { Thread.sleep(600L); } catch(Exception e) { }
400         assertEquals("Should be zero idle, found " + pool.getNumIdle(""),0,pool.getNumIdle(""));
401 
402         for(int i=0;i<500;i++) {
403             active[i] = pool.borrowObject("");
404         }
405         for(int i=0;i<500;i++) {
406             pool.returnObject("",active[i]);
407         }
408 
409         try { Thread.sleep(1000L); } catch(Exception e) { }
410         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 500);
411         try { Thread.sleep(600L); } catch(Exception e) { }
412         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 400);
413         try { Thread.sleep(600L); } catch(Exception e) { }
414         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 300);
415         try { Thread.sleep(600L); } catch(Exception e) { }
416         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 200);
417         try { Thread.sleep(600L); } catch(Exception e) { }
418         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 100);
419         try { Thread.sleep(600L); } catch(Exception e) { }
420         assertEquals("Should be zero idle, found " + pool.getNumIdle(""),0,pool.getNumIdle(""));
421     }
422 
423     public void testEviction2() throws Exception {
424         pool.setMaxIdle(500);
425         pool.setMaxActive(500);
426         pool.setNumTestsPerEvictionRun(100);
427         pool.setMinEvictableIdleTimeMillis(500L);
428         pool.setTimeBetweenEvictionRunsMillis(500L);
429 
430         Object[] active = new Object[500];
431         Object[] active2 = new Object[500];
432         for(int i=0;i<500;i++) {
433             active[i] = pool.borrowObject("");
434             active2[i] = pool.borrowObject("2");
435         }
436         for(int i=0;i<500;i++) {
437             pool.returnObject("",active[i]);
438             pool.returnObject("2",active2[i]);
439         }
440 
441         try { Thread.sleep(1000L); } catch(Exception e) { }
442         assertTrue("Should be less than 1000 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 1000);
443         try { Thread.sleep(600L); } catch(Exception e) { }
444         assertTrue("Should be less than 900 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 900);
445         try { Thread.sleep(600L); } catch(Exception e) { }
446         assertTrue("Should be less than 800 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 800);
447         try { Thread.sleep(600L); } catch(Exception e) { }
448         assertTrue("Should be less than 700 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 700);
449         try { Thread.sleep(600L); } catch(Exception e) { }
450         assertTrue("Should be less than 600 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 600);
451         try { Thread.sleep(600L); } catch(Exception e) { }
452         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
453         try { Thread.sleep(600L); } catch(Exception e) { }
454         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
455         try { Thread.sleep(600L); } catch(Exception e) { }
456         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
457         try { Thread.sleep(600L); } catch(Exception e) { }
458         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
459         try { Thread.sleep(600L); } catch(Exception e) { }
460         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
461         try { Thread.sleep(600L); } catch(Exception e) { }
462         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
463     }
464 
465     /***
466      * Kicks off <numThreads> test threads, each of which will go through
467      * <iterations> borrow-return cycles with random delay times <= delay
468      * in between.
469      */
470     public void runTestThreads(int numThreads, int iterations, int delay) {
471         TestThread[] threads = new TestThread[numThreads];
472         for(int i=0;i<numThreads;i++) {
473             threads[i] = new TestThread(pool,iterations,delay);
474             Thread t = new Thread(threads[i]);
475             t.start();
476         }
477         for(int i=0;i<numThreads;i++) {
478             while(!(threads[i]).complete()) {
479                 try {
480                     Thread.sleep(500L);
481                 } catch(Exception e) {
482                     // ignored
483                 }
484             }
485             if(threads[i].failed()) {
486                 fail();
487             }
488         }
489     }
490     
491     public void testThreaded1() throws Exception {
492         pool.setMaxActive(15);
493         pool.setMaxIdle(15);
494         pool.setMaxWait(1000L);
495         runTestThreads(20, 100, 50);
496     }
497     
498     /***
499      * Verifies that maxTotal is not exceeded when factory destroyObject
500      * has high latency, testOnReturn is set and there is high incidence of
501      * validation failures. 
502      */
503     public void testMaxTotalInvariant() throws Exception {
504         int maxTotal = 15;
505         SimpleFactory factory = new SimpleFactory();
506         factory.setEvenValid(false);     // Every other validation fails
507         factory.setDestroyLatency(100);  // Destroy takes 100 ms
508         factory.setMaxActive(maxTotal);  // (makes - destroys) bound
509         factory.setValidationEnabled(true);
510         pool = new GenericKeyedObjectPool(factory);
511         pool.setMaxTotal(maxTotal);
512         pool.setMaxIdle(-1);
513         pool.setTestOnReturn(true);
514         pool.setMaxWait(10000L);
515         runTestThreads(5, 10, 50);
516     }
517 
518     public void testMinIdle() throws Exception {
519         pool.setMaxIdle(500);
520         pool.setMinIdle(5);
521         pool.setMaxActive(10);
522         pool.setNumTestsPerEvictionRun(0);
523         pool.setMinEvictableIdleTimeMillis(50L);
524         pool.setTimeBetweenEvictionRunsMillis(100L);
525         pool.setTestWhileIdle(true);
526 
527 
528         //Generate a random key
529         String key = "A";
530 
531         pool.preparePool(key, true);
532 
533         try { Thread.sleep(150L); } catch(Exception e) { }
534         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
535 
536         Object[] active = new Object[5];
537         active[0] = pool.borrowObject(key);
538 
539         try { Thread.sleep(150L); } catch(Exception e) { }
540         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
541 
542         for(int i=1 ; i<5 ; i++) {
543             active[i] = pool.borrowObject(key);
544         }
545 
546         try { Thread.sleep(150L); } catch(Exception e) { }
547         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
548 
549         for(int i=0 ; i<5 ; i++) {
550             pool.returnObject(key, active[i]);
551         }
552 
553         try { Thread.sleep(150L); } catch(Exception e) { }
554         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
555     }
556 
557     public void testMinIdleMaxActive() throws Exception {
558         pool.setMaxIdle(500);
559         pool.setMinIdle(5);
560         pool.setMaxActive(10);
561         pool.setNumTestsPerEvictionRun(0);
562         pool.setMinEvictableIdleTimeMillis(50L);
563         pool.setTimeBetweenEvictionRunsMillis(100L);
564         pool.setTestWhileIdle(true);
565 
566         String key = "A";
567 
568         pool.preparePool(key, true);
569         assertTrue("Should be 5 idle, found " + 
570                 pool.getNumIdle(),pool.getNumIdle() == 5);
571 
572         try { Thread.sleep(150L); } catch(Exception e) { }
573         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
574 
575         Object[] active = new Object[10];
576 
577         try { Thread.sleep(150L); } catch(Exception e) { }
578         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
579 
580         for(int i=0 ; i<5 ; i++) {
581             active[i] = pool.borrowObject(key);
582         }
583 
584         try { Thread.sleep(150L); } catch(Exception e) { }
585         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
586 
587         for(int i=0 ; i<5 ; i++) {
588             pool.returnObject(key, active[i]);
589         }
590 
591         try { Thread.sleep(150L); } catch(Exception e) { }
592         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
593 
594         for(int i=0 ; i<10 ; i++) {
595             active[i] = pool.borrowObject(key);
596         }
597 
598         try { Thread.sleep(150L); } catch(Exception e) { }
599         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
600 
601         for(int i=0 ; i<10 ; i++) {
602             pool.returnObject(key, active[i]);
603         }
604 
605         try { Thread.sleep(150L); } catch(Exception e) { }
606         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
607     }
608 
609     public void testMinIdleNoPopulateImmediately() throws Exception {
610         pool.setMaxIdle(500);
611         pool.setMinIdle(5);
612         pool.setMaxActive(10);
613         pool.setNumTestsPerEvictionRun(0);
614         pool.setMinEvictableIdleTimeMillis(50L);
615         pool.setTimeBetweenEvictionRunsMillis(1000L);
616         pool.setTestWhileIdle(true);
617 
618 
619         //Generate a random key
620         String key = "A";
621 
622         pool.preparePool(key, false);
623 
624         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
625 
626         try { Thread.sleep(1500L); } catch(Exception e) { }
627         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
628     }
629 
630     public void testMinIdleNoPreparePool() throws Exception {
631         pool.setMaxIdle(500);
632         pool.setMinIdle(5);
633         pool.setMaxActive(10);
634         pool.setNumTestsPerEvictionRun(0);
635         pool.setMinEvictableIdleTimeMillis(50L);
636         pool.setTimeBetweenEvictionRunsMillis(100L);
637         pool.setTestWhileIdle(true);
638 
639 
640         //Generate a random key
641         String key = "A";
642 
643         try { Thread.sleep(150L); } catch(Exception e) { }
644         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
645 
646         Object active = pool.borrowObject(key);
647         assertNotNull(active);
648 
649         try { Thread.sleep(150L); } catch(Exception e) { }
650         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
651     }
652 
653     public void testFIFO() throws Exception {
654         pool.setLifo(false);
655         final Object key = "key";
656         pool.addObject(key); // "key0"
657         pool.addObject(key); // "key1"
658         pool.addObject(key); // "key2"
659         assertEquals("Oldest", "key0", pool.borrowObject(key));
660         assertEquals("Middle", "key1", pool.borrowObject(key));
661         assertEquals("Youngest", "key2", pool.borrowObject(key));
662         assertEquals("new-3", "key3", pool.borrowObject(key));
663         pool.returnObject(key, "r");
664         assertEquals("returned", "r", pool.borrowObject(key));
665         assertEquals("new-4", "key4", pool.borrowObject(key));
666     }
667     
668     public void testLIFO() throws Exception {
669         pool.setLifo(true);
670         final Object key = "key";
671         pool.addObject(key); // "key0"
672         pool.addObject(key); // "key1"
673         pool.addObject(key); // "key2"
674         assertEquals("Youngest", "key2", pool.borrowObject(key));
675         assertEquals("Middle", "key1", pool.borrowObject(key));
676         assertEquals("Oldest", "key0", pool.borrowObject(key));
677         assertEquals("new-3", "key3", pool.borrowObject(key));
678         pool.returnObject(key, "r");
679         assertEquals("returned", "r", pool.borrowObject(key));
680         assertEquals("new-4", "key4", pool.borrowObject(key));
681     }
682     
683     /***
684      * Test to make sure evictor visits least recently used objects first,
685      * regardless of FIFO/LIFO 
686      * 
687      * JIRA: POOL-86
688      */ 
689     public void testEvictionOrder() throws Exception {
690         checkEvictionOrder(false);
691         checkEvictionOrder(true);
692     }
693     
694     private void checkEvictionOrder(boolean lifo) throws Exception {
695         SimpleFactory factory = new SimpleFactory();
696         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
697         pool.setNumTestsPerEvictionRun(2);
698         pool.setMinEvictableIdleTimeMillis(100);
699         pool.setLifo(lifo);
700         
701         for (int i = 0; i < 3; i ++) {
702             Integer key = new Integer(i);
703             for (int j = 0; j < 5; j++) {
704                 pool.addObject(key);
705             }
706         }
707         
708         // Make all evictable
709         Thread.sleep(200);
710         
711         /* 
712          * Initial state (Key, Object) pairs in order of age:
713          * 
714          * (0,0), (0,1), (0,2), (0,3), (0,4)
715          * (1,5), (1,6), (1,7), (1,8), (1,9)
716          * (2,10), (2,11), (2,12), (2,13), (2,14)
717          */
718         
719         pool.evict(); // Kill (0,0),(0,1)
720         assertEquals(3, pool.getNumIdle(zero));
721         Object obj = pool.borrowObject(zero);
722         assertTrue(lifo ? obj.equals("04") : obj.equals("02"));
723         assertEquals(2, pool.getNumIdle(zero));
724         obj = pool.borrowObject(zero);
725         assertTrue(obj.equals("03"));
726         assertEquals(1, pool.getNumIdle(zero));
727         
728         pool.evict(); // Kill remaining 0 survivor and (1,5)
729         assertEquals(0, pool.getNumIdle(zero));
730         assertEquals(4, pool.getNumIdle(one));
731         obj = pool.borrowObject(one);
732         assertTrue(lifo ? obj.equals("19") : obj.equals("16"));
733         assertEquals(3, pool.getNumIdle(one));
734         obj = pool.borrowObject(one);
735         assertTrue(lifo ? obj.equals("18") : obj.equals("17"));
736         assertEquals(2, pool.getNumIdle(one));
737         
738         pool.evict(); // Kill remaining 1 survivors
739         assertEquals(0, pool.getNumIdle(one));
740         pool.evict(); // Kill (2,10), (2,11)
741         assertEquals(3, pool.getNumIdle(two));
742         obj = pool.borrowObject(two);
743         assertTrue(lifo ? obj.equals("214") : obj.equals("212"));
744         assertEquals(2, pool.getNumIdle(two));
745         pool.evict(); // All dead now
746         assertEquals(0, pool.getNumIdle(two));  
747         
748         pool.evict(); // Should do nothing - make sure no exception
749         pool.evict();
750         
751         // Reload
752         pool.setMinEvictableIdleTimeMillis(500);
753         factory.counter = 0; // Reset counter
754         for (int i = 0; i < 3; i ++) {
755             Integer key = new Integer(i);
756             for (int j = 0; j < 5; j++) {
757                 pool.addObject(key);
758             }
759             Thread.sleep(200);
760         }
761         
762         // 0's are evictable, others not 
763         pool.evict(); // Kill (0,0),(0,1)
764         assertEquals(3, pool.getNumIdle(zero));
765         pool.evict(); // Kill (0,2),(0,3)
766         assertEquals(1, pool.getNumIdle(zero));
767         pool.evict(); // Kill (0,4), leave (1,5)
768         assertEquals(0, pool.getNumIdle(zero));
769         assertEquals(5, pool.getNumIdle(one));
770         assertEquals(5, pool.getNumIdle(two));
771         pool.evict(); // (1,6), (1,7)
772         assertEquals(5, pool.getNumIdle(one));
773         assertEquals(5, pool.getNumIdle(two));
774         pool.evict(); // (1,8), (1,9)
775         assertEquals(5, pool.getNumIdle(one));
776         assertEquals(5, pool.getNumIdle(two));
777         pool.evict(); // (2,10), (2,11)
778         assertEquals(5, pool.getNumIdle(one));
779         assertEquals(5, pool.getNumIdle(two));
780         pool.evict(); // (2,12), (2,13)
781         assertEquals(5, pool.getNumIdle(one));
782         assertEquals(5, pool.getNumIdle(two));
783         pool.evict(); // (2,14), (1,5)
784         assertEquals(5, pool.getNumIdle(one));
785         assertEquals(5, pool.getNumIdle(two));
786         Thread.sleep(200); // Ones now timed out
787         pool.evict(); // kill (1,6), (1,7) - (1,5) missed
788         assertEquals(3, pool.getNumIdle(one));
789         assertEquals(5, pool.getNumIdle(two));
790         obj = pool.borrowObject(one);
791         assertTrue(lifo ? obj.equals("19") : obj.equals("15"));  
792     }
793     
794     
795     /***
796      * Verifies that the evictor visits objects in expected order
797      * and frequency. 
798      */
799     public void testEvictorVisiting() throws Exception {
800         checkEvictorVisiting(true);
801         checkEvictorVisiting(false);  
802     }
803     
804     private void checkEvictorVisiting(boolean lifo) throws Exception {
805         VisitTrackerFactory factory = new VisitTrackerFactory();
806         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
807         pool.setNumTestsPerEvictionRun(2);
808         pool.setMinEvictableIdleTimeMillis(-1);
809         pool.setTestWhileIdle(true);
810         pool.setLifo(lifo);
811         pool.setTestOnReturn(false);
812         pool.setTestOnBorrow(false);
813         for (int i = 0; i < 3; i ++) {
814             factory.resetId();
815             Integer key = new Integer(i);
816             for (int j = 0; j < 8; j++) {
817                 pool.addObject(key);
818             }
819         }
820         pool.evict(); // Visit oldest 2 - 00 and 01
821         Object obj = pool.borrowObject(zero);
822         pool.returnObject(zero, obj);
823         obj = pool.borrowObject(zero);
824         pool.returnObject(zero, obj);
825         //  borrow, return, borrow, return 
826         //  FIFO will move 0 and 1 to end - 2,3,4,5,6,7,0,1
827         //  LIFO, 7 out, then in, then out, then in - 7,6,5,4,3,2,1,0
828         pool.evict();  // Should visit 02 and 03 in either case
829         for (int i = 0; i < 8; i++) {
830             VisitTracker tracker = (VisitTracker) pool.borrowObject(zero);    
831             if (tracker.getId() >= 4) {
832                 assertEquals("Unexpected instance visited " + tracker.getId(),
833                         0, tracker.getValidateCount());
834             } else {
835                 assertEquals("Instance " +  tracker.getId() + 
836                         " visited wrong number of times.",
837                         1, tracker.getValidateCount());
838             }
839         } 
840         // 0's are all out
841         
842         pool.setNumTestsPerEvictionRun(3);
843         
844         pool.evict(); // 10, 11, 12
845         pool.evict(); // 13, 14, 15
846         
847         obj = pool.borrowObject(one);
848         pool.returnObject(one, obj);
849         obj = pool.borrowObject(one);
850         pool.returnObject(one, obj);
851         obj = pool.borrowObject(one);
852         pool.returnObject(one, obj);
853         // borrow, return, borrow, return 
854         //  FIFO 3,4,5,^,6,7,0,1,2
855         //  LIFO 7,6,^,5,4,3,2,1,0
856         // In either case, pointer should be at 6
857         pool.evict();
858         // LIFO - 16, 17, 20
859         // FIFO - 16, 17, 10
860         pool.evict();
861         // LIFO - 21, 22, 23
862         // FIFO - 11, 12, 20
863         pool.evict();
864         // LIFO - 24, 25, 26
865         // FIFO - 21, 22, 23
866         pool.evict();
867         // LIFO - 27, skip, 10
868         // FIFO - 24, 25, 26
869         for (int i = 0; i < 8; i++) {
870             VisitTracker tracker = (VisitTracker) pool.borrowObject(one);    
871             if ((lifo && tracker.getId() > 0) || 
872                     (!lifo && tracker.getId() > 2)) {
873                 assertEquals("Instance " +  tracker.getId() + 
874                         " visited wrong number of times.",
875                         1, tracker.getValidateCount());
876             } else {
877                 assertEquals("Instance " +  tracker.getId() + 
878                         " visited wrong number of times.",
879                         2, tracker.getValidateCount());
880             }
881         } 
882         
883         // Randomly generate some pools with random numTests
884         // and make sure evictor cycles through elements appropriately
885         int[] smallPrimes = {2, 3, 5, 7};
886         Random random = new Random();
887         random.setSeed(System.currentTimeMillis());
888         pool.setMaxIdle(-1);
889         for (int i = 0; i < 4; i++) {
890             pool.setNumTestsPerEvictionRun(smallPrimes[i]);
891             for (int j = 0; j < 5; j++) {
892                 pool.clear();
893                 int zeroLength = 10 + random.nextInt(20);
894                 for (int k = 0; k < zeroLength; k++) {
895                     pool.addObject(zero);
896                 }
897                 int oneLength = 10 + random.nextInt(20);
898                 for (int k = 0; k < oneLength; k++) {
899                     pool.addObject(one);
900                 }
901                 int twoLength = 10 + random.nextInt(20);
902                 for (int k = 0; k < twoLength; k++) {
903                     pool.addObject(two);
904                 }
905                 
906                 // Choose a random number of evictor runs
907                 int runs = 10 + random.nextInt(50);
908                 for (int k = 0; k < runs; k++) {
909                     pool.evict();
910                 }
911                 
912                 // Total instances in pool
913                 int totalInstances = zeroLength + oneLength + twoLength;
914                 
915                 // Number of times evictor should have cycled through pools
916                 int cycleCount = (runs * pool.getNumTestsPerEvictionRun())
917                     / totalInstances;
918                 
919                 // Look at elements and make sure they are visited cycleCount
920                 // or cycleCount + 1 times
921                 VisitTracker tracker = null;
922                 int visitCount = 0;
923                 for (int k = 0; k < zeroLength; k++) {
924                     tracker = (VisitTracker) pool.borrowObject(zero); 
925                     visitCount = tracker.getValidateCount();                  
926                     assertTrue(visitCount >= cycleCount && 
927                             visitCount <= cycleCount + 1);
928                 }
929                 for (int k = 0; k < oneLength; k++) {
930                     tracker = (VisitTracker) pool.borrowObject(one); 
931                     visitCount = tracker.getValidateCount();
932                     assertTrue(visitCount >= cycleCount && 
933                             visitCount <= cycleCount + 1);
934                 }
935                 for (int k = 0; k < twoLength; k++) {
936                     tracker = (VisitTracker) pool.borrowObject(two); 
937                     visitCount = tracker.getValidateCount();
938                     assertTrue(visitCount >= cycleCount && 
939                             visitCount <= cycleCount + 1);
940                 } 
941             }
942         }
943     }
944     
945     public void testConstructors() {
946         
947         // Make constructor arguments all different from defaults
948         int maxActive = 1;
949         int maxIdle = 2;
950         long maxWait = 3;
951         int minIdle = 4;
952         int maxTotal = 5;
953         long minEvictableIdleTimeMillis = 6;
954         int numTestsPerEvictionRun = 7;
955         boolean testOnBorrow = true;
956         boolean testOnReturn = true;
957         boolean testWhileIdle = true;
958         long timeBetweenEvictionRunsMillis = 8;
959         byte whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
960         boolean lifo = false;
961         
962         GenericKeyedObjectPool pool = new GenericKeyedObjectPool();
963         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_ACTIVE, pool.getMaxActive());
964         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
965         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_WAIT, pool.getMaxWait());
966         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
967         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
968         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
969                 pool.getMinEvictableIdleTimeMillis());
970         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
971                 pool.getNumTestsPerEvictionRun());
972         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
973                 pool.getTestOnBorrow());
974         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
975                 pool.getTestOnReturn());
976         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
977                 pool.getTestWhileIdle());
978         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
979                 pool.getTimeBetweenEvictionRunsMillis());
980         assertEquals(GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION,
981                 pool.getWhenExhaustedAction());
982         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
983         
984         GenericKeyedObjectPool.Config config = new GenericKeyedObjectPool.Config();
985         config.lifo = lifo;
986         config.maxActive = maxActive;
987         config.maxIdle = maxIdle;
988         config.minIdle = minIdle;
989         config.maxTotal = maxTotal;
990         config.maxWait = maxWait;
991         config.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
992         config.numTestsPerEvictionRun = numTestsPerEvictionRun;
993         config.testOnBorrow = testOnBorrow;
994         config.testOnReturn = testOnReturn;
995         config.testWhileIdle = testWhileIdle;
996         config.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
997         config.whenExhaustedAction = whenExhaustedAction;
998         pool = new GenericKeyedObjectPool(null, config);
999         assertEquals(maxActive, pool.getMaxActive());
1000         assertEquals(maxIdle, pool.getMaxIdle());
1001         assertEquals(maxWait, pool.getMaxWait());
1002         assertEquals(minIdle, pool.getMinIdle());
1003         assertEquals(maxTotal, pool.getMaxTotal());
1004         assertEquals(minEvictableIdleTimeMillis,
1005                 pool.getMinEvictableIdleTimeMillis());
1006         assertEquals(numTestsPerEvictionRun, pool.getNumTestsPerEvictionRun());
1007         assertEquals(testOnBorrow,pool.getTestOnBorrow());
1008         assertEquals(testOnReturn,pool.getTestOnReturn());
1009         assertEquals(testWhileIdle,pool.getTestWhileIdle());
1010         assertEquals(timeBetweenEvictionRunsMillis,
1011                 pool.getTimeBetweenEvictionRunsMillis());
1012         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1013         assertEquals(lifo, pool.getLifo());
1014         
1015         pool = new GenericKeyedObjectPool(null, maxActive);
1016         assertEquals(maxActive, pool.getMaxActive());
1017         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1018         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_WAIT, pool.getMaxWait());
1019         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1020         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1021         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1022                 pool.getMinEvictableIdleTimeMillis());
1023         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1024                 pool.getNumTestsPerEvictionRun());
1025         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1026                 pool.getTestOnBorrow());
1027         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1028                 pool.getTestOnReturn());
1029         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1030                 pool.getTestWhileIdle());
1031         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1032                 pool.getTimeBetweenEvictionRunsMillis());
1033         assertEquals(GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION,
1034                 pool.getWhenExhaustedAction());
1035         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1036         
1037         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction, maxWait);
1038         assertEquals(maxActive, pool.getMaxActive());
1039         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1040         assertEquals(maxWait, pool.getMaxWait());
1041         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1042         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1043         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1044                 pool.getMinEvictableIdleTimeMillis());
1045         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1046                 pool.getNumTestsPerEvictionRun());
1047         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1048                 pool.getTestOnBorrow());
1049         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1050                 pool.getTestOnReturn());
1051         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1052                 pool.getTestWhileIdle());
1053         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1054                 pool.getTimeBetweenEvictionRunsMillis());
1055         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1056         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1057         
1058         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1059                    maxWait, testOnBorrow, testOnReturn);
1060         assertEquals(maxActive, pool.getMaxActive());
1061         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1062         assertEquals(maxWait, pool.getMaxWait());
1063         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1064         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1065         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1066                 pool.getMinEvictableIdleTimeMillis());
1067         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1068                 pool.getNumTestsPerEvictionRun());
1069         assertEquals(testOnBorrow,pool.getTestOnBorrow());
1070         assertEquals(testOnReturn,pool.getTestOnReturn());
1071         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1072                 pool.getTestWhileIdle());
1073         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1074                 pool.getTimeBetweenEvictionRunsMillis());
1075         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1076         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1077         
1078         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1079                 maxWait, maxIdle);
1080         assertEquals(maxActive, pool.getMaxActive());
1081         assertEquals(maxIdle, pool.getMaxIdle());
1082         assertEquals(maxWait, pool.getMaxWait());
1083         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1084         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1085         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1086                 pool.getMinEvictableIdleTimeMillis());
1087         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1088                 pool.getNumTestsPerEvictionRun());
1089         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1090                 pool.getTestOnBorrow());
1091         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1092                 pool.getTestOnReturn());
1093         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1094                 pool.getTestWhileIdle());
1095         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1096                 pool.getTimeBetweenEvictionRunsMillis());
1097         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1098         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1099 
1100         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1101                 maxWait, maxIdle, testOnBorrow, testOnReturn);
1102         assertEquals(maxActive, pool.getMaxActive());
1103         assertEquals(maxIdle, pool.getMaxIdle());
1104         assertEquals(maxWait, pool.getMaxWait());
1105         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1106         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1107         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1108                 pool.getMinEvictableIdleTimeMillis());
1109         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1110                 pool.getNumTestsPerEvictionRun());
1111         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1112         assertEquals(testOnReturn, pool.getTestOnReturn());
1113         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1114                 pool.getTestWhileIdle());
1115         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1116                 pool.getTimeBetweenEvictionRunsMillis());
1117         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1118         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1119 
1120         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1121                 maxWait, maxIdle, testOnBorrow, testOnReturn,
1122                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1123                 minEvictableIdleTimeMillis, testWhileIdle);
1124         assertEquals(maxActive, pool.getMaxActive());
1125         assertEquals(maxIdle, pool.getMaxIdle());
1126         assertEquals(maxWait, pool.getMaxWait());
1127         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1128         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1129         assertEquals(minEvictableIdleTimeMillis,
1130                 pool.getMinEvictableIdleTimeMillis());
1131         assertEquals(numTestsPerEvictionRun,
1132                 pool.getNumTestsPerEvictionRun());
1133         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1134         assertEquals(testOnReturn, pool.getTestOnReturn());
1135         assertEquals(testWhileIdle,
1136                 pool.getTestWhileIdle());
1137         assertEquals(timeBetweenEvictionRunsMillis,
1138                 pool.getTimeBetweenEvictionRunsMillis());
1139         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1140         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1141         
1142         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1143                 maxWait, maxIdle, maxTotal, testOnBorrow, testOnReturn,
1144                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1145                 minEvictableIdleTimeMillis, testWhileIdle);
1146         assertEquals(maxActive, pool.getMaxActive());
1147         assertEquals(maxIdle, pool.getMaxIdle());
1148         assertEquals(maxWait, pool.getMaxWait());
1149         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1150         assertEquals(maxTotal, pool.getMaxTotal());
1151         assertEquals(minEvictableIdleTimeMillis,
1152                 pool.getMinEvictableIdleTimeMillis());
1153         assertEquals(numTestsPerEvictionRun,
1154                 pool.getNumTestsPerEvictionRun());
1155         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1156         assertEquals(testOnReturn, pool.getTestOnReturn());
1157         assertEquals(testWhileIdle,
1158                 pool.getTestWhileIdle());
1159         assertEquals(timeBetweenEvictionRunsMillis,
1160                 pool.getTimeBetweenEvictionRunsMillis());
1161         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1162         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1163         
1164         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1165                 maxWait, maxIdle, maxTotal, minIdle, testOnBorrow, testOnReturn,
1166                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1167                 minEvictableIdleTimeMillis, testWhileIdle);
1168         assertEquals(maxActive, pool.getMaxActive());
1169         assertEquals(maxIdle, pool.getMaxIdle());
1170         assertEquals(maxWait, pool.getMaxWait());
1171         assertEquals(minIdle, pool.getMinIdle());
1172         assertEquals(maxTotal, pool.getMaxTotal());
1173         assertEquals(minEvictableIdleTimeMillis,
1174                 pool.getMinEvictableIdleTimeMillis());
1175         assertEquals(numTestsPerEvictionRun,
1176                 pool.getNumTestsPerEvictionRun());
1177         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1178         assertEquals(testOnReturn, pool.getTestOnReturn());
1179         assertEquals(testWhileIdle,
1180                 pool.getTestWhileIdle());
1181         assertEquals(timeBetweenEvictionRunsMillis,
1182                 pool.getTimeBetweenEvictionRunsMillis());
1183         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1184         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1185         
1186         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1187                 maxWait, maxIdle, maxTotal, minIdle, testOnBorrow, testOnReturn,
1188                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1189                 minEvictableIdleTimeMillis, testWhileIdle, lifo);
1190         assertEquals(maxActive, pool.getMaxActive());
1191         assertEquals(maxIdle, pool.getMaxIdle());
1192         assertEquals(maxWait, pool.getMaxWait());
1193         assertEquals(minIdle, pool.getMinIdle());
1194         assertEquals(maxTotal, pool.getMaxTotal());
1195         assertEquals(minEvictableIdleTimeMillis,
1196                 pool.getMinEvictableIdleTimeMillis());
1197         assertEquals(numTestsPerEvictionRun,
1198                 pool.getNumTestsPerEvictionRun());
1199         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1200         assertEquals(testOnReturn, pool.getTestOnReturn());
1201         assertEquals(testWhileIdle,
1202                 pool.getTestWhileIdle());
1203         assertEquals(timeBetweenEvictionRunsMillis,
1204                 pool.getTimeBetweenEvictionRunsMillis());
1205         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1206         assertEquals(lifo, pool.getLifo());  
1207     }
1208 
1209     class TestThread implements Runnable {
1210         java.util.Random _random = new java.util.Random();
1211         KeyedObjectPool _pool = null;
1212         boolean _complete = false;
1213         boolean _failed = false;
1214         int _iter = 100;
1215         int _delay = 50;
1216 
1217         public TestThread(KeyedObjectPool pool) {
1218             _pool = pool;
1219         }
1220 
1221         public TestThread(KeyedObjectPool pool, int iter) {
1222             _pool = pool;
1223             _iter = iter;
1224         }
1225 
1226         public TestThread(KeyedObjectPool pool, int iter, int delay) {
1227             _pool = pool;
1228             _iter = iter;
1229             _delay = delay;
1230         }
1231 
1232         public boolean complete() {
1233             return _complete;
1234         }
1235 
1236         public boolean failed() {
1237             return _failed;
1238         }
1239 
1240         public void run() {
1241             for(int i=0;i<_iter;i++) {
1242                 String key = String.valueOf(_random.nextInt(3));
1243                 try {
1244                     Thread.sleep((long)_random.nextInt(_delay));
1245                 } catch(Exception e) {
1246                     // ignored
1247                 }
1248                 Object obj = null;
1249                 try {
1250                     obj = _pool.borrowObject(key);
1251                 } catch(Exception e) {
1252                     e.printStackTrace();
1253                     _failed = true;
1254                     _complete = true;
1255                     break;
1256                 }
1257 
1258                 try {
1259                     Thread.sleep((long)_random.nextInt(_delay));
1260                 } catch(Exception e) {
1261                     // ignored
1262                 }
1263                 try {
1264                     _pool.returnObject(key,obj);
1265                 } catch(Exception e) {
1266                     e.printStackTrace();
1267                     _failed = true;
1268                     _complete = true;
1269                     break;
1270                 }
1271             }
1272             _complete = true;
1273         }
1274     }
1275 
1276     static class SimpleFactory implements KeyedPoolableObjectFactory {
1277         public SimpleFactory() {
1278             this(true);
1279         }
1280         public SimpleFactory(boolean valid) {
1281             this.valid = valid;
1282         }
1283         public Object makeObject(Object key) {
1284             synchronized(this) {
1285                 activeCount++;
1286                 if (activeCount > maxActive) {
1287                     throw new IllegalStateException(
1288                         "Too many active instances: " + activeCount);
1289                 }
1290             }
1291             return String.valueOf(key) + String.valueOf(counter++);
1292         }
1293         public void destroyObject(Object key, Object obj) {
1294             doWait(destroyLatency);
1295             synchronized(this) {
1296                 activeCount--;
1297             }
1298         }
1299         public boolean validateObject(Object key, Object obj) {
1300             if (enableValidation) { 
1301                 return validateCounter++%2 == 0 ? evenValid : oddValid; 
1302             } else {
1303                 return valid;
1304             }
1305         }
1306         public void activateObject(Object key, Object obj) { }
1307         public void passivateObject(Object key, Object obj) { }
1308         
1309         public void setMaxActive(int maxActive) {
1310             this.maxActive = maxActive;
1311         }
1312         public void setDestroyLatency(long destroyLatency) {
1313             this.destroyLatency = destroyLatency;
1314         }
1315         public void setValidationEnabled(boolean b) {
1316             enableValidation = b;
1317         }
1318         void setEvenValid(boolean valid) {
1319             evenValid = valid;
1320         }
1321         
1322         int counter = 0;
1323         boolean valid;
1324         
1325         int activeCount = 0;
1326         int validateCounter = 0;
1327         boolean evenValid = true;
1328         boolean oddValid = true;
1329         boolean enableValidation = false;
1330         long destroyLatency = 0;
1331         int maxActive = Integer.MAX_VALUE;
1332         
1333         private void doWait(long latency) {
1334             try {
1335                 Thread.sleep(latency);
1336             } catch (InterruptedException ex) {
1337                 // ignore
1338             }
1339         }
1340     }
1341 
1342     protected boolean isLifo() {
1343         return true;
1344     }
1345 
1346     protected boolean isFifo() {
1347         return false;
1348     }
1349 
1350 }
1351 
1352