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.impl;
19  
20  import java.io.PrintWriter;
21  import java.io.StringWriter;
22  import java.util.HashMap;
23  import java.util.NoSuchElementException;
24  import java.util.Random;
25  
26  import org.apache.commons.pool.KeyedObjectPool;
27  import org.apache.commons.pool.KeyedPoolableObjectFactory;
28  import org.apache.commons.pool.TestBaseKeyedObjectPool;
29  import org.apache.commons.pool.VisitTracker;
30  import org.apache.commons.pool.VisitTrackerFactory;
31  import org.apache.commons.pool.WaiterFactory;
32  
33  /**
34   * @author Rodney Waldhoff
35   * @version $Revision: 1206483 $ $Date: 2011-11-26 09:37:34 -0700 (Sat, 26 Nov 2011) $
36   */
37  public class TestGenericKeyedObjectPool extends TestBaseKeyedObjectPool {
38      public TestGenericKeyedObjectPool(String testName) {
39          super(testName);
40      }
41  
42      protected KeyedObjectPool makeEmptyPool(int mincapacity) {
43          GenericKeyedObjectPool pool = new GenericKeyedObjectPool(
44              new KeyedPoolableObjectFactory()  {
45                  HashMap map = new HashMap();
46                  public Object makeObject(Object key) {
47                      int counter = 0;
48                      Integer Counter = (Integer)(map.get(key));
49                      if(null != Counter) {
50                          counter = Counter.intValue();
51                      }
52                      map.put(key,new Integer(counter + 1));
53                      return String.valueOf(key) + String.valueOf(counter);
54                  }
55                  public void destroyObject(Object key, Object obj) { }
56                  public boolean validateObject(Object key, Object obj) { return true; }
57                  public void activateObject(Object key, Object obj) { }
58                  public void passivateObject(Object key, Object obj) { }
59              }
60          );
61          pool.setMaxActive(mincapacity);
62          pool.setMaxIdle(mincapacity);
63          return pool;
64      }
65  
66      protected KeyedObjectPool makeEmptyPool(KeyedPoolableObjectFactory factory) {
67          return new GenericKeyedObjectPool(factory);
68      }
69  
70      protected Object getNthObject(Object key, int n) {
71          return String.valueOf(key) + String.valueOf(n);
72      }
73  
74      protected Object makeKey(int n) {
75          return String.valueOf(n);
76      }
77  
78      private GenericKeyedObjectPool pool = null;
79      private final Integer zero = new Integer(0);
80      private final Integer one = new Integer(1);
81      private final Integer two = new Integer(2);
82  
83      public void setUp() throws Exception {
84          super.setUp();
85          pool = new GenericKeyedObjectPool(new SimpleFactory());
86      }
87  
88      public void tearDown() throws Exception {
89          super.tearDown();
90          pool.clear();
91          pool.close();
92          pool = null;
93      }
94  
95      public void testNegativeMaxActive() throws Exception {
96          pool.setMaxActive(-1);
97          pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
98          Object obj = pool.borrowObject("");
99          assertEquals("0",obj);
100         pool.returnObject("",obj);
101     }
102 
103     public void testNumActiveNumIdle2() throws Exception {
104         assertEquals(0,pool.getNumActive());
105         assertEquals(0,pool.getNumIdle());
106         assertEquals(0,pool.getNumActive("A"));
107         assertEquals(0,pool.getNumIdle("A"));
108         assertEquals(0,pool.getNumActive("B"));
109         assertEquals(0,pool.getNumIdle("B"));
110 
111         Object objA0 = pool.borrowObject("A");
112         Object objB0 = pool.borrowObject("B");
113 
114         assertEquals(2,pool.getNumActive());
115         assertEquals(0,pool.getNumIdle());
116         assertEquals(1,pool.getNumActive("A"));
117         assertEquals(0,pool.getNumIdle("A"));
118         assertEquals(1,pool.getNumActive("B"));
119         assertEquals(0,pool.getNumIdle("B"));
120 
121         Object objA1 = pool.borrowObject("A");
122         Object objB1 = pool.borrowObject("B");
123 
124         assertEquals(4,pool.getNumActive());
125         assertEquals(0,pool.getNumIdle());
126         assertEquals(2,pool.getNumActive("A"));
127         assertEquals(0,pool.getNumIdle("A"));
128         assertEquals(2,pool.getNumActive("B"));
129         assertEquals(0,pool.getNumIdle("B"));
130 
131         pool.returnObject("A",objA0);
132         pool.returnObject("B",objB0);
133 
134         assertEquals(2,pool.getNumActive());
135         assertEquals(2,pool.getNumIdle());
136         assertEquals(1,pool.getNumActive("A"));
137         assertEquals(1,pool.getNumIdle("A"));
138         assertEquals(1,pool.getNumActive("B"));
139         assertEquals(1,pool.getNumIdle("B"));
140 
141         pool.returnObject("A",objA1);
142         pool.returnObject("B",objB1);
143 
144         assertEquals(0,pool.getNumActive());
145         assertEquals(4,pool.getNumIdle());
146         assertEquals(0,pool.getNumActive("A"));
147         assertEquals(2,pool.getNumIdle("A"));
148         assertEquals(0,pool.getNumActive("B"));
149         assertEquals(2,pool.getNumIdle("B"));
150     }
151 
152     public void testMaxIdle() throws Exception {
153         pool.setMaxActive(100);
154         pool.setMaxIdle(8);
155         Object[] active = new Object[100];
156         for(int i=0;i<100;i++) {
157             active[i] = pool.borrowObject("");
158         }
159         assertEquals(100,pool.getNumActive(""));
160         assertEquals(0,pool.getNumIdle(""));
161         for(int i=0;i<100;i++) {
162             pool.returnObject("",active[i]);
163             assertEquals(99 - i,pool.getNumActive(""));
164             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle(""));
165         }
166         
167         for(int i=0;i<100;i++) {
168             active[i] = pool.borrowObject("a");
169         }
170         assertEquals(100,pool.getNumActive("a"));
171         assertEquals(0,pool.getNumIdle("a"));
172         for(int i=0;i<100;i++) {
173             pool.returnObject("a",active[i]);
174             assertEquals(99 - i,pool.getNumActive("a"));
175             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle("a"));
176         }
177         
178         // total number of idle instances is twice maxIdle
179         assertEquals(16, pool.getNumIdle());
180         // Each pool is at the sup
181         assertEquals(8, pool.getNumIdle(""));
182         assertEquals(8, pool.getNumIdle("a"));
183              
184     }
185 
186     public void testMaxActive() throws Exception {
187         pool.setMaxActive(3);
188         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
189 
190         pool.borrowObject("");
191         pool.borrowObject("");
192         pool.borrowObject("");
193         try {
194             pool.borrowObject("");
195             fail("Expected NoSuchElementException");
196         } catch(NoSuchElementException e) {
197             // expected
198         }
199     }
200 
201     public void testMaxActiveZero() throws Exception {
202         pool.setMaxActive(0);
203         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
204 
205         try {
206             pool.borrowObject("a");
207             fail("Expected NoSuchElementException");
208         } catch(NoSuchElementException e) {
209             // expected
210         }
211     }
212     
213     public void testWhenExhaustedGrow() throws Exception {
214         pool.setMaxActive(1);
215         pool.setMaxTotal(1);
216         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW);
217         for (int i = 0; i < 10; i++) {
218             pool.borrowObject("a");
219         }
220     }
221 
222     public void testWhenExhaustedBlockClosePool() throws Exception {
223         pool.setMaxActive(1);
224         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
225         pool.setMaxWait(0);
226         Object obj1 = pool.borrowObject("a");
227         
228         // Make sure an object was obtained
229         assertNotNull(obj1);
230         
231         // Create a separate thread to try and borrow another object
232         WaitingTestThread wtt = new WaitingTestThread(pool, "a", 200);
233         wtt.start();
234         // Give wtt time to start
235         Thread.sleep(200);
236         
237         // close the pool (Bug POOL-189)
238         pool.close();
239         
240         // Give interrupt time to take effect
241         Thread.sleep(200);
242         
243         // Check thread was interrupted
244         assertTrue(wtt._thrown instanceof IllegalStateException);
245     }
246 
247     public void testMaxTotal() throws Exception {
248         pool.setMaxActive(2);
249         pool.setMaxTotal(3);
250         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
251 
252         Object o1 = pool.borrowObject("a");
253         assertNotNull(o1);
254         Object o2 = pool.borrowObject("a");
255         assertNotNull(o2);
256         Object o3 = pool.borrowObject("b");
257         assertNotNull(o3);
258         try {
259             pool.borrowObject("c");
260             fail("Expected NoSuchElementException");
261         } catch(NoSuchElementException e) {
262             // expected
263         }
264 
265         assertEquals(0, pool.getNumIdle());
266 
267         pool.returnObject("b", o3);
268         assertEquals(1, pool.getNumIdle());
269         assertEquals(1, pool.getNumIdle("b"));
270 
271         Object o4 = pool.borrowObject("b");
272         assertNotNull(o4);
273         assertEquals(0, pool.getNumIdle());
274         assertEquals(0, pool.getNumIdle("b"));
275         
276         pool.setMaxTotal(4);
277         Object o5 = pool.borrowObject("b");
278         assertNotNull(o5);
279         
280         assertEquals(2, pool.getNumActive("a"));
281         assertEquals(2, pool.getNumActive("b"));
282         assertEquals(pool.getMaxTotal(),
283                 pool.getNumActive("b") + pool.getNumActive("b"));
284         assertEquals(pool.getNumActive(),
285                 pool.getMaxTotal());
286     }
287 
288     public void testMaxTotalZero() throws Exception {
289         pool.setMaxTotal(0);
290         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
291 
292         try {
293             pool.borrowObject("a");
294             fail("Expected NoSuchElementException");
295         } catch(NoSuchElementException e) {
296             // expected
297         }
298     }
299 
300     public void testMaxTotalLRU() throws Exception {
301         pool.setMaxActive(2);
302         pool.setMaxTotal(3);
303 //        pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW);
304 
305         Object o1 = pool.borrowObject("a");
306         assertNotNull(o1);
307         pool.returnObject("a", o1);
308         Thread.sleep(25);
309 
310         Object o2 = pool.borrowObject("b");
311         assertNotNull(o2);
312         pool.returnObject("b", o2);
313         Thread.sleep(25);
314 
315         Object o3 = pool.borrowObject("c");
316         assertNotNull(o3);
317         pool.returnObject("c", o3);
318         Thread.sleep(25);
319 
320         Object o4 = pool.borrowObject("a");
321         assertNotNull(o4);
322         pool.returnObject("a", o4);
323         Thread.sleep(25);
324 
325         assertSame(o1, o4);
326 
327         // this should cause b to be bumped out of the pool
328         Object o5 = pool.borrowObject("d");
329         assertNotNull(o5);
330         pool.returnObject("d", o5);
331         Thread.sleep(25);
332 
333         // now re-request b, we should get a different object because it should
334         // have been expelled from pool (was oldest because a was requested after b)
335         Object o6 = pool.borrowObject("b");
336         assertNotNull(o6);
337         pool.returnObject("b", o6);
338 
339         assertNotSame(o1, o6);
340 
341         // second a is still in there
342         Object o7 = pool.borrowObject("a");
343         assertNotNull(o7);
344         pool.returnObject("a", o7);
345 
346         assertSame(o4, o7);
347     }
348 
349     public void testSettersAndGetters() throws Exception {
350         GenericKeyedObjectPool pool = new GenericKeyedObjectPool();
351         {
352             pool.setFactory(new SimpleFactory());
353         }
354         {
355             pool.setMaxActive(123);
356             assertEquals(123,pool.getMaxActive());
357         }
358         {
359             pool.setMaxIdle(12);
360             assertEquals(12,pool.getMaxIdle());
361         }
362         {
363             pool.setMaxWait(1234L);
364             assertEquals(1234L,pool.getMaxWait());
365         }
366         {
367             pool.setMinEvictableIdleTimeMillis(12345L);
368             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
369         }
370         {
371             pool.setNumTestsPerEvictionRun(11);
372             assertEquals(11,pool.getNumTestsPerEvictionRun());
373         }
374         {
375             pool.setTestOnBorrow(true);
376             assertTrue(pool.getTestOnBorrow());
377             pool.setTestOnBorrow(false);
378             assertTrue(!pool.getTestOnBorrow());
379         }
380         {
381             pool.setTestOnReturn(true);
382             assertTrue(pool.getTestOnReturn());
383             pool.setTestOnReturn(false);
384             assertTrue(!pool.getTestOnReturn());
385         }
386         {
387             pool.setTestWhileIdle(true);
388             assertTrue(pool.getTestWhileIdle());
389             pool.setTestWhileIdle(false);
390             assertTrue(!pool.getTestWhileIdle());
391         }
392         {
393             pool.setTimeBetweenEvictionRunsMillis(11235L);
394             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
395         }
396         {
397             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK);
398             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK,pool.getWhenExhaustedAction());
399             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
400             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_FAIL,pool.getWhenExhaustedAction());
401             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW);
402             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_GROW,pool.getWhenExhaustedAction());
403         }
404     }
405 
406     public void testEviction() throws Exception {
407         pool.setMaxIdle(500);
408         pool.setMaxActive(500);
409         pool.setNumTestsPerEvictionRun(100);
410         pool.setMinEvictableIdleTimeMillis(250L);
411         pool.setTimeBetweenEvictionRunsMillis(500L);
412 
413         Object[] active = new Object[500];
414         for(int i=0;i<500;i++) {
415             active[i] = pool.borrowObject("");
416         }
417         for(int i=0;i<500;i++) {
418             pool.returnObject("",active[i]);
419         }
420 
421         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
422         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 500);
423         try { Thread.sleep(600L); } catch(InterruptedException e) { }
424         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 400);
425         try { Thread.sleep(600L); } catch(InterruptedException e) { }
426         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 300);
427         try { Thread.sleep(600L); } catch(InterruptedException e) { }
428         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 200);
429         try { Thread.sleep(600L); } catch(InterruptedException e) { }
430         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 100);
431         try { Thread.sleep(600L); } catch(InterruptedException e) { }
432         assertEquals("Should be zero idle, found " + pool.getNumIdle(""),0,pool.getNumIdle(""));
433 
434         for(int i=0;i<500;i++) {
435             active[i] = pool.borrowObject("");
436         }
437         for(int i=0;i<500;i++) {
438             pool.returnObject("",active[i]);
439         }
440 
441         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
442         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 500);
443         try { Thread.sleep(600L); } catch(InterruptedException e) { }
444         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 400);
445         try { Thread.sleep(600L); } catch(InterruptedException e) { }
446         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 300);
447         try { Thread.sleep(600L); } catch(InterruptedException e) { }
448         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 200);
449         try { Thread.sleep(600L); } catch(InterruptedException e) { }
450         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 100);
451         try { Thread.sleep(600L); } catch(InterruptedException e) { }
452         assertEquals("Should be zero idle, found " + pool.getNumIdle(""),0,pool.getNumIdle(""));
453     }
454 
455     public void testEviction2() throws Exception {
456         pool.setMaxIdle(500);
457         pool.setMaxActive(500);
458         pool.setNumTestsPerEvictionRun(100);
459         pool.setMinEvictableIdleTimeMillis(500L);
460         pool.setTimeBetweenEvictionRunsMillis(500L);
461 
462         Object[] active = new Object[500];
463         Object[] active2 = new Object[500];
464         for(int i=0;i<500;i++) {
465             active[i] = pool.borrowObject("");
466             active2[i] = pool.borrowObject("2");
467         }
468         for(int i=0;i<500;i++) {
469             pool.returnObject("",active[i]);
470             pool.returnObject("2",active2[i]);
471         }
472 
473         try { Thread.sleep(1100L); } catch(InterruptedException e) { }
474         assertTrue("Should be less than 1000 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 1000);
475         try { Thread.sleep(600L); } catch(InterruptedException e) { }
476         assertTrue("Should be less than 900 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 900);
477         try { Thread.sleep(600L); } catch(InterruptedException e) { }
478         assertTrue("Should be less than 800 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 800);
479         try { Thread.sleep(600L); } catch(InterruptedException e) { }
480         assertTrue("Should be less than 700 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 700);
481         try { Thread.sleep(600L); } catch(InterruptedException e) { }
482         assertTrue("Should be less than 600 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 600);
483         try { Thread.sleep(600L); } catch(InterruptedException e) { }
484         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
485         try { Thread.sleep(600L); } catch(InterruptedException e) { }
486         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
487         try { Thread.sleep(600L); } catch(InterruptedException e) { }
488         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
489         try { Thread.sleep(600L); } catch(InterruptedException e) { }
490         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
491         try { Thread.sleep(600L); } catch(InterruptedException e) { }
492         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
493         try { Thread.sleep(600L); } catch(InterruptedException e) { }
494         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
495     }
496 
497     /**
498      * Kicks off <numThreads> test threads, each of which will go through
499      * <iterations> borrow-return cycles with random delay times <= delay
500      * in between.
501      */
502     public void runTestThreads(int numThreads, int iterations, int delay) {
503         TestThread[] threads = new TestThread[numThreads];
504         for(int i=0;i<numThreads;i++) {
505             threads[i] = new TestThread(pool,iterations,delay);
506             Thread t = new Thread(threads[i]);
507             t.start();
508         }
509         for(int i=0;i<numThreads;i++) {
510             while(!(threads[i]).complete()) {
511                 try {
512                     Thread.sleep(500L);
513                 } catch(InterruptedException e) {
514                     // ignored
515                 }
516             }
517             if(threads[i].failed()) {
518                 fail("Thread failed: "+i+"\n"+getExceptionTrace(threads[i]._exception));
519             }
520         }
521     }
522     
523     public void testThreaded1() throws Exception {
524         pool.setMaxActive(15);
525         pool.setMaxIdle(15);
526         pool.setMaxWait(1000L);
527         runTestThreads(20, 100, 50);
528     }
529     
530     /**
531      * Verifies that maxTotal is not exceeded when factory destroyObject
532      * has high latency, testOnReturn is set and there is high incidence of
533      * validation failures. 
534      */
535     public void testMaxTotalInvariant() throws Exception {
536         int maxTotal = 15;
537         SimpleFactory factory = new SimpleFactory();
538         factory.setEvenValid(false);     // Every other validation fails
539         factory.setDestroyLatency(100);  // Destroy takes 100 ms
540         factory.setMaxActive(maxTotal);  // (makes - destroys) bound
541         factory.setValidationEnabled(true);
542         pool = new GenericKeyedObjectPool(factory);
543         pool.setMaxTotal(maxTotal);
544         pool.setMaxIdle(-1);
545         pool.setTestOnReturn(true);
546         pool.setMaxWait(10000L);
547         runTestThreads(5, 10, 50);
548     }
549 
550     public void testMinIdle() throws Exception {
551         pool.setMaxIdle(500);
552         pool.setMinIdle(5);
553         pool.setMaxActive(10);
554         pool.setNumTestsPerEvictionRun(0);
555         pool.setMinEvictableIdleTimeMillis(50L);
556         pool.setTimeBetweenEvictionRunsMillis(100L);
557         pool.setTestWhileIdle(true);
558 
559 
560         //Generate a random key
561         String key = "A";
562 
563         pool.preparePool(key, true);
564 
565         try { Thread.sleep(150L); } catch(InterruptedException e) { }
566         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
567 
568         Object[] active = new Object[5];
569         active[0] = pool.borrowObject(key);
570 
571         try { Thread.sleep(150L); } catch(InterruptedException e) { }
572         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
573 
574         for(int i=1 ; i<5 ; i++) {
575             active[i] = pool.borrowObject(key);
576         }
577 
578         try { Thread.sleep(150L); } catch(InterruptedException e) { }
579         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
580 
581         for(int i=0 ; i<5 ; i++) {
582             pool.returnObject(key, active[i]);
583         }
584 
585         try { Thread.sleep(150L); } catch(InterruptedException e) { }
586         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
587     }
588 
589     public void testMinIdleMaxActive() throws Exception {
590         pool.setMaxIdle(500);
591         pool.setMinIdle(5);
592         pool.setMaxActive(10);
593         pool.setNumTestsPerEvictionRun(0);
594         pool.setMinEvictableIdleTimeMillis(50L);
595         pool.setTimeBetweenEvictionRunsMillis(100L);
596         pool.setTestWhileIdle(true);
597 
598         String key = "A";
599 
600         pool.preparePool(key, true);
601         assertTrue("Should be 5 idle, found " + 
602                 pool.getNumIdle(),pool.getNumIdle() == 5);
603 
604         try { Thread.sleep(150L); } catch(InterruptedException e) { }
605         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
606 
607         Object[] active = new Object[10];
608 
609         try { Thread.sleep(150L); } catch(InterruptedException e) { }
610         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
611 
612         for(int i=0 ; i<5 ; i++) {
613             active[i] = pool.borrowObject(key);
614         }
615 
616         try { Thread.sleep(150L); } catch(InterruptedException e) { }
617         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
618 
619         for(int i=0 ; i<5 ; i++) {
620             pool.returnObject(key, active[i]);
621         }
622 
623         try { Thread.sleep(150L); } catch(InterruptedException e) { }
624         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
625 
626         for(int i=0 ; i<10 ; i++) {
627             active[i] = pool.borrowObject(key);
628         }
629 
630         try { Thread.sleep(150L); } catch(InterruptedException e) { }
631         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
632 
633         for(int i=0 ; i<10 ; i++) {
634             pool.returnObject(key, active[i]);
635         }
636 
637         try { Thread.sleep(150L); } catch(InterruptedException e) { }
638         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
639     }
640 
641     public void testMinIdleNoPopulateImmediately() throws Exception {
642         pool.setMaxIdle(500);
643         pool.setMinIdle(5);
644         pool.setMaxActive(10);
645         pool.setNumTestsPerEvictionRun(0);
646         pool.setMinEvictableIdleTimeMillis(50L);
647         pool.setTimeBetweenEvictionRunsMillis(1000L);
648         pool.setTestWhileIdle(true);
649 
650 
651         //Generate a random key
652         String key = "A";
653 
654         pool.preparePool(key, false);
655 
656         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
657 
658         try { Thread.sleep(1500L); } catch(InterruptedException e) { }
659         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
660     }
661 
662     public void testMinIdleNoPreparePool() throws Exception {
663         pool.setMaxIdle(500);
664         pool.setMinIdle(5);
665         pool.setMaxActive(10);
666         pool.setNumTestsPerEvictionRun(0);
667         pool.setMinEvictableIdleTimeMillis(50L);
668         pool.setTimeBetweenEvictionRunsMillis(100L);
669         pool.setTestWhileIdle(true);
670 
671 
672         //Generate a random key
673         String key = "A";
674 
675         try { Thread.sleep(150L); } catch(InterruptedException e) { }
676         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
677 
678         Object active = pool.borrowObject(key);
679         assertNotNull(active);
680 
681         try { Thread.sleep(150L); } catch(InterruptedException e) { }
682         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
683     }
684 
685     public void testFIFO() throws Exception {
686         pool.setLifo(false);
687         final Object key = "key";
688         pool.addObject(key); // "key0"
689         pool.addObject(key); // "key1"
690         pool.addObject(key); // "key2"
691         assertEquals("Oldest", "key0", pool.borrowObject(key));
692         assertEquals("Middle", "key1", pool.borrowObject(key));
693         assertEquals("Youngest", "key2", pool.borrowObject(key));
694         assertEquals("new-3", "key3", pool.borrowObject(key));
695         pool.returnObject(key, "r");
696         assertEquals("returned", "r", pool.borrowObject(key));
697         assertEquals("new-4", "key4", pool.borrowObject(key));
698     }
699     
700     public void testLIFO() throws Exception {
701         pool.setLifo(true);
702         final Object key = "key";
703         pool.addObject(key); // "key0"
704         pool.addObject(key); // "key1"
705         pool.addObject(key); // "key2"
706         assertEquals("Youngest", "key2", pool.borrowObject(key));
707         assertEquals("Middle", "key1", pool.borrowObject(key));
708         assertEquals("Oldest", "key0", pool.borrowObject(key));
709         assertEquals("new-3", "key3", pool.borrowObject(key));
710         pool.returnObject(key, "r");
711         assertEquals("returned", "r", pool.borrowObject(key));
712         assertEquals("new-4", "key4", pool.borrowObject(key));
713     }
714     
715     /**
716      * Test to make sure evictor visits least recently used objects first,
717      * regardless of FIFO/LIFO 
718      * 
719      * JIRA: POOL-86
720      */ 
721     public void testEvictionOrder() throws Exception {
722         checkEvictionOrder(false);
723         checkEvictionOrder(true);
724     }
725     
726     private void checkEvictionOrder(boolean lifo) throws Exception {
727         SimpleFactory factory = new SimpleFactory();
728         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
729         pool.setNumTestsPerEvictionRun(2);
730         pool.setMinEvictableIdleTimeMillis(100);
731         pool.setLifo(lifo);
732         
733         for (int i = 0; i < 3; i ++) {
734             Integer key = new Integer(i);
735             for (int j = 0; j < 5; j++) {
736                 pool.addObject(key);
737             }
738         }
739         
740         // Make all evictable
741         Thread.sleep(200);
742         
743         /* 
744          * Initial state (Key, Object) pairs in order of age:
745          * 
746          * (0,0), (0,1), (0,2), (0,3), (0,4)
747          * (1,5), (1,6), (1,7), (1,8), (1,9)
748          * (2,10), (2,11), (2,12), (2,13), (2,14)
749          */
750         
751         pool.evict(); // Kill (0,0),(0,1)
752         assertEquals(3, pool.getNumIdle(zero));
753         Object objZeroA = pool.borrowObject(zero);
754         assertTrue(lifo ? objZeroA.equals("04") : objZeroA.equals("02"));
755         assertEquals(2, pool.getNumIdle(zero));
756         Object objZeroB = pool.borrowObject(zero);
757         assertTrue(objZeroB.equals("03"));
758         assertEquals(1, pool.getNumIdle(zero));
759         
760         pool.evict(); // Kill remaining 0 survivor and (1,5)
761         assertEquals(0, pool.getNumIdle(zero));
762         assertEquals(4, pool.getNumIdle(one));
763         Object objOneA = pool.borrowObject(one);
764         assertTrue(lifo ? objOneA.equals("19") : objOneA.equals("16"));
765         assertEquals(3, pool.getNumIdle(one));
766         Object objOneB = pool.borrowObject(one);
767         assertTrue(lifo ? objOneB.equals("18") : objOneB.equals("17"));
768         assertEquals(2, pool.getNumIdle(one));
769         
770         pool.evict(); // Kill remaining 1 survivors
771         assertEquals(0, pool.getNumIdle(one));
772         pool.evict(); // Kill (2,10), (2,11)
773         assertEquals(3, pool.getNumIdle(two));
774         Object objTwoA = pool.borrowObject(two);
775         assertTrue(lifo ? objTwoA.equals("214") : objTwoA.equals("212"));
776         assertEquals(2, pool.getNumIdle(two));
777         pool.evict(); // All dead now
778         assertEquals(0, pool.getNumIdle(two));  
779         
780         pool.evict(); // Should do nothing - make sure no exception
781         // Currently 2 zero, 2 one and 1 two active. Return them
782         pool.returnObject(zero, objZeroA);
783         pool.returnObject(zero, objZeroB);
784         pool.returnObject(one, objOneA);
785         pool.returnObject(one, objOneB);
786         pool.returnObject(two, objTwoA);
787         // Remove all idle objects
788         pool.clear();
789         
790         // Reload
791         pool.setMinEvictableIdleTimeMillis(500);
792         factory.counter = 0; // Reset counter
793         for (int i = 0; i < 3; i ++) {
794             Integer key = new Integer(i);
795             for (int j = 0; j < 5; j++) {
796                 pool.addObject(key);
797             }
798             Thread.sleep(200);
799         }
800         
801         // 0's are evictable, others not 
802         pool.evict(); // Kill (0,0),(0,1)
803         assertEquals(3, pool.getNumIdle(zero));
804         pool.evict(); // Kill (0,2),(0,3)
805         assertEquals(1, pool.getNumIdle(zero));
806         pool.evict(); // Kill (0,4), leave (1,5)
807         assertEquals(0, pool.getNumIdle(zero));
808         assertEquals(5, pool.getNumIdle(one));
809         assertEquals(5, pool.getNumIdle(two));
810         pool.evict(); // (1,6), (1,7)
811         assertEquals(5, pool.getNumIdle(one));
812         assertEquals(5, pool.getNumIdle(two));
813         pool.evict(); // (1,8), (1,9)
814         assertEquals(5, pool.getNumIdle(one));
815         assertEquals(5, pool.getNumIdle(two));
816         pool.evict(); // (2,10), (2,11)
817         assertEquals(5, pool.getNumIdle(one));
818         assertEquals(5, pool.getNumIdle(two));
819         pool.evict(); // (2,12), (2,13)
820         assertEquals(5, pool.getNumIdle(one));
821         assertEquals(5, pool.getNumIdle(two));
822         pool.evict(); // (2,14), (1,5)
823         assertEquals(5, pool.getNumIdle(one));
824         assertEquals(5, pool.getNumIdle(two));
825         Thread.sleep(200); // Ones now timed out
826         pool.evict(); // kill (1,6), (1,7) - (1,5) missed
827         assertEquals(3, pool.getNumIdle(one));
828         assertEquals(5, pool.getNumIdle(two));
829         Object obj = pool.borrowObject(one);
830         if (lifo) {
831             assertEquals("19", obj);
832         } else {
833             assertEquals("15", obj);
834         }
835     }
836     
837     
838     /**
839      * Verifies that the evictor visits objects in expected order
840      * and frequency. 
841      */
842     public void testEvictorVisiting() throws Exception {
843         checkEvictorVisiting(true);
844         checkEvictorVisiting(false);  
845     }
846     
847     private void checkEvictorVisiting(boolean lifo) throws Exception {
848         VisitTrackerFactory factory = new VisitTrackerFactory();
849         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
850         pool.setNumTestsPerEvictionRun(2);
851         pool.setMinEvictableIdleTimeMillis(-1);
852         pool.setTestWhileIdle(true);
853         pool.setLifo(lifo);
854         pool.setTestOnReturn(false);
855         pool.setTestOnBorrow(false);
856         for (int i = 0; i < 3; i ++) {
857             factory.resetId();
858             Integer key = new Integer(i);
859             for (int j = 0; j < 8; j++) {
860                 pool.addObject(key);
861             }
862         }
863         pool.evict(); // Visit oldest 2 - 00 and 01
864         Object obj = pool.borrowObject(zero);
865         pool.returnObject(zero, obj);
866         obj = pool.borrowObject(zero);
867         pool.returnObject(zero, obj);
868         //  borrow, return, borrow, return 
869         //  FIFO will move 0 and 1 to end - 2,3,4,5,6,7,0,1
870         //  LIFO, 7 out, then in, then out, then in - 7,6,5,4,3,2,1,0
871         pool.evict();  // Should visit 02 and 03 in either case
872         for (int i = 0; i < 8; i++) {
873             VisitTracker tracker = (VisitTracker) pool.borrowObject(zero);    
874             if (tracker.getId() >= 4) {
875                 assertEquals("Unexpected instance visited " + tracker.getId(),
876                         0, tracker.getValidateCount());
877             } else {
878                 assertEquals("Instance " +  tracker.getId() + 
879                         " visited wrong number of times.",
880                         1, tracker.getValidateCount());
881             }
882         } 
883         // 0's are all out
884         
885         pool.setNumTestsPerEvictionRun(3);
886         
887         pool.evict(); // 10, 11, 12
888         pool.evict(); // 13, 14, 15
889         
890         obj = pool.borrowObject(one);
891         pool.returnObject(one, obj);
892         obj = pool.borrowObject(one);
893         pool.returnObject(one, obj);
894         obj = pool.borrowObject(one);
895         pool.returnObject(one, obj);
896         // borrow, return, borrow, return 
897         //  FIFO 3,4,5,^,6,7,0,1,2
898         //  LIFO 7,6,^,5,4,3,2,1,0
899         // In either case, pointer should be at 6
900         pool.evict();
901         // LIFO - 16, 17, 20
902         // FIFO - 16, 17, 10
903         pool.evict();
904         // LIFO - 21, 22, 23
905         // FIFO - 11, 12, 20
906         pool.evict();
907         // LIFO - 24, 25, 26
908         // FIFO - 21, 22, 23
909         pool.evict();
910         // LIFO - 27, skip, 10
911         // FIFO - 24, 25, 26
912         for (int i = 0; i < 8; i++) {
913             VisitTracker tracker = (VisitTracker) pool.borrowObject(one);    
914             if ((lifo && tracker.getId() > 0) || 
915                     (!lifo && tracker.getId() > 2)) {
916                 assertEquals("Instance " +  tracker.getId() + 
917                         " visited wrong number of times.",
918                         1, tracker.getValidateCount());
919             } else {
920                 assertEquals("Instance " +  tracker.getId() + 
921                         " visited wrong number of times.",
922                         2, tracker.getValidateCount());
923             }
924         } 
925         
926         // Randomly generate some pools with random numTests
927         // and make sure evictor cycles through elements appropriately
928         int[] smallPrimes = {2, 3, 5, 7};
929         Random random = new Random();
930         random.setSeed(System.currentTimeMillis());
931         pool.setMaxIdle(-1);
932         for (int i = 0; i < smallPrimes.length; i++) {
933             pool.setNumTestsPerEvictionRun(smallPrimes[i]);
934             for (int j = 0; j < 5; j++) {// Try the tests a few times
935                 pool.clear();
936                 assertEquals("NumIdle should be zero after clearing the pool",0,pool.getNumIdle());
937                 int zeroLength = 10 + random.nextInt(20);
938                 for (int k = 0; k < zeroLength; k++) {
939                     pool.addObject(zero);
940                 }
941                 int oneLength = 10 + random.nextInt(20);
942                 for (int k = 0; k < oneLength; k++) {
943                     pool.addObject(one);
944                 }
945                 int twoLength = 10 + random.nextInt(20);
946                 for (int k = 0; k < twoLength; k++) {
947                     pool.addObject(two);
948                 }
949                 
950                 // Choose a random number of evictor runs
951                 int runs = 10 + random.nextInt(50);
952                 for (int k = 0; k < runs; k++) {
953                     pool.evict();
954                 }
955                 
956                 // Total instances in pool
957                 int totalInstances = zeroLength + oneLength + twoLength;
958                 
959                 // Number of times evictor should have cycled through pools
960                 int cycleCount = (runs * pool.getNumTestsPerEvictionRun())
961                     / totalInstances;
962                 
963                 // Look at elements and make sure they are visited cycleCount
964                 // or cycleCount + 1 times
965                 VisitTracker tracker = null;
966                 int visitCount = 0;
967                 for (int k = 0; k < zeroLength; k++) {
968                     tracker = (VisitTracker) pool.borrowObject(zero); 
969                     visitCount = tracker.getValidateCount();
970                     if (visitCount < cycleCount || visitCount > cycleCount + 1){
971                         fail(formatSettings("ZERO", "runs", runs, "lifo", lifo, "i", i, "j", j,
972                                 "k", k, "visitCount", visitCount, "cycleCount", cycleCount,
973                                 "totalInstances", totalInstances, zeroLength, oneLength, twoLength));
974                     }
975                 }
976                 for (int k = 0; k < oneLength; k++) {
977                     tracker = (VisitTracker) pool.borrowObject(one); 
978                     visitCount = tracker.getValidateCount();
979                     if (visitCount < cycleCount || visitCount > cycleCount + 1){
980                         fail(formatSettings("ONE", "runs", runs, "lifo", lifo, "i", i, "j", j,
981                                 "k", k, "visitCount", visitCount, "cycleCount", cycleCount,
982                                 "totalInstances", totalInstances, zeroLength, oneLength, twoLength));
983                     }
984                 }
985                 int visits[] = new int[twoLength];
986                 for (int k = 0; k < twoLength; k++) {
987                     tracker = (VisitTracker) pool.borrowObject(two); 
988                     visitCount = tracker.getValidateCount();
989                     visits[k] = visitCount;
990                     if (visitCount < cycleCount || visitCount > cycleCount + 1){
991                         StringBuffer sb = new StringBuffer("Visits:");
992                         for (int l = 0; l <= k; l++){
993                             sb.append(visits[l]).append(' ');
994                         }
995                         fail(formatSettings("TWO "+sb.toString(), "runs", runs, "lifo", lifo, "i", i, "j", j,
996                                 "k", k, "visitCount", visitCount, "cycleCount", cycleCount,
997                                 "totalInstances", totalInstances, zeroLength, oneLength, twoLength));
998                     }
999                 }
1000             }
1001         }
1002     }
1003     
1004     public void testConstructors() {
1005         
1006         // Make constructor arguments all different from defaults
1007         int maxActive = 1;
1008         int maxIdle = 2;
1009         long maxWait = 3;
1010         int minIdle = 4;
1011         int maxTotal = 5;
1012         long minEvictableIdleTimeMillis = 6;
1013         int numTestsPerEvictionRun = 7;
1014         boolean testOnBorrow = true;
1015         boolean testOnReturn = true;
1016         boolean testWhileIdle = true;
1017         long timeBetweenEvictionRunsMillis = 8;
1018         byte whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
1019         boolean lifo = false;
1020         
1021         GenericKeyedObjectPool pool = new GenericKeyedObjectPool();
1022         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_ACTIVE, pool.getMaxActive());
1023         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1024         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_WAIT, pool.getMaxWait());
1025         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1026         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1027         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1028                 pool.getMinEvictableIdleTimeMillis());
1029         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1030                 pool.getNumTestsPerEvictionRun());
1031         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1032                 pool.getTestOnBorrow());
1033         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1034                 pool.getTestOnReturn());
1035         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1036                 pool.getTestWhileIdle());
1037         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1038                 pool.getTimeBetweenEvictionRunsMillis());
1039         assertEquals(GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION,
1040                 pool.getWhenExhaustedAction());
1041         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1042         
1043         GenericKeyedObjectPool.Config config = new GenericKeyedObjectPool.Config();
1044         config.lifo = lifo;
1045         config.maxActive = maxActive;
1046         config.maxIdle = maxIdle;
1047         config.minIdle = minIdle;
1048         config.maxTotal = maxTotal;
1049         config.maxWait = maxWait;
1050         config.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
1051         config.numTestsPerEvictionRun = numTestsPerEvictionRun;
1052         config.testOnBorrow = testOnBorrow;
1053         config.testOnReturn = testOnReturn;
1054         config.testWhileIdle = testWhileIdle;
1055         config.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
1056         config.whenExhaustedAction = whenExhaustedAction;
1057         pool = new GenericKeyedObjectPool(null, config);
1058         assertEquals(maxActive, pool.getMaxActive());
1059         assertEquals(maxIdle, pool.getMaxIdle());
1060         assertEquals(maxWait, pool.getMaxWait());
1061         assertEquals(minIdle, pool.getMinIdle());
1062         assertEquals(maxTotal, pool.getMaxTotal());
1063         assertEquals(minEvictableIdleTimeMillis,
1064                 pool.getMinEvictableIdleTimeMillis());
1065         assertEquals(numTestsPerEvictionRun, pool.getNumTestsPerEvictionRun());
1066         assertEquals(testOnBorrow,pool.getTestOnBorrow());
1067         assertEquals(testOnReturn,pool.getTestOnReturn());
1068         assertEquals(testWhileIdle,pool.getTestWhileIdle());
1069         assertEquals(timeBetweenEvictionRunsMillis,
1070                 pool.getTimeBetweenEvictionRunsMillis());
1071         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1072         assertEquals(lifo, pool.getLifo());
1073         
1074         pool = new GenericKeyedObjectPool(null, maxActive);
1075         assertEquals(maxActive, pool.getMaxActive());
1076         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1077         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_WAIT, pool.getMaxWait());
1078         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1079         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1080         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1081                 pool.getMinEvictableIdleTimeMillis());
1082         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1083                 pool.getNumTestsPerEvictionRun());
1084         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1085                 pool.getTestOnBorrow());
1086         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1087                 pool.getTestOnReturn());
1088         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1089                 pool.getTestWhileIdle());
1090         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1091                 pool.getTimeBetweenEvictionRunsMillis());
1092         assertEquals(GenericKeyedObjectPool.DEFAULT_WHEN_EXHAUSTED_ACTION,
1093                 pool.getWhenExhaustedAction());
1094         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1095         
1096         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction, maxWait);
1097         assertEquals(maxActive, pool.getMaxActive());
1098         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1099         assertEquals(maxWait, pool.getMaxWait());
1100         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1101         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1102         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1103                 pool.getMinEvictableIdleTimeMillis());
1104         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1105                 pool.getNumTestsPerEvictionRun());
1106         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1107                 pool.getTestOnBorrow());
1108         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1109                 pool.getTestOnReturn());
1110         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1111                 pool.getTestWhileIdle());
1112         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1113                 pool.getTimeBetweenEvictionRunsMillis());
1114         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1115         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1116         
1117         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1118                    maxWait, testOnBorrow, testOnReturn);
1119         assertEquals(maxActive, pool.getMaxActive());
1120         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_IDLE, pool.getMaxIdle());
1121         assertEquals(maxWait, pool.getMaxWait());
1122         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1123         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1124         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1125                 pool.getMinEvictableIdleTimeMillis());
1126         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1127                 pool.getNumTestsPerEvictionRun());
1128         assertEquals(testOnBorrow,pool.getTestOnBorrow());
1129         assertEquals(testOnReturn,pool.getTestOnReturn());
1130         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1131                 pool.getTestWhileIdle());
1132         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1133                 pool.getTimeBetweenEvictionRunsMillis());
1134         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1135         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1136         
1137         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1138                 maxWait, maxIdle);
1139         assertEquals(maxActive, pool.getMaxActive());
1140         assertEquals(maxIdle, pool.getMaxIdle());
1141         assertEquals(maxWait, pool.getMaxWait());
1142         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1143         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1144         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1145                 pool.getMinEvictableIdleTimeMillis());
1146         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1147                 pool.getNumTestsPerEvictionRun());
1148         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_BORROW,
1149                 pool.getTestOnBorrow());
1150         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_ON_RETURN,
1151                 pool.getTestOnReturn());
1152         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1153                 pool.getTestWhileIdle());
1154         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1155                 pool.getTimeBetweenEvictionRunsMillis());
1156         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1157         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1158 
1159         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1160                 maxWait, maxIdle, testOnBorrow, testOnReturn);
1161         assertEquals(maxActive, pool.getMaxActive());
1162         assertEquals(maxIdle, pool.getMaxIdle());
1163         assertEquals(maxWait, pool.getMaxWait());
1164         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1165         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1166         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
1167                 pool.getMinEvictableIdleTimeMillis());
1168         assertEquals(GenericKeyedObjectPool.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
1169                 pool.getNumTestsPerEvictionRun());
1170         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1171         assertEquals(testOnReturn, pool.getTestOnReturn());
1172         assertEquals(GenericKeyedObjectPool.DEFAULT_TEST_WHILE_IDLE,
1173                 pool.getTestWhileIdle());
1174         assertEquals(GenericKeyedObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
1175                 pool.getTimeBetweenEvictionRunsMillis());
1176         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1177         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1178 
1179         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1180                 maxWait, maxIdle, testOnBorrow, testOnReturn,
1181                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1182                 minEvictableIdleTimeMillis, testWhileIdle);
1183         assertEquals(maxActive, pool.getMaxActive());
1184         assertEquals(maxIdle, pool.getMaxIdle());
1185         assertEquals(maxWait, pool.getMaxWait());
1186         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1187         assertEquals(GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, pool.getMaxTotal());
1188         assertEquals(minEvictableIdleTimeMillis,
1189                 pool.getMinEvictableIdleTimeMillis());
1190         assertEquals(numTestsPerEvictionRun,
1191                 pool.getNumTestsPerEvictionRun());
1192         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1193         assertEquals(testOnReturn, pool.getTestOnReturn());
1194         assertEquals(testWhileIdle,
1195                 pool.getTestWhileIdle());
1196         assertEquals(timeBetweenEvictionRunsMillis,
1197                 pool.getTimeBetweenEvictionRunsMillis());
1198         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1199         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1200         
1201         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1202                 maxWait, maxIdle, maxTotal, testOnBorrow, testOnReturn,
1203                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1204                 minEvictableIdleTimeMillis, testWhileIdle);
1205         assertEquals(maxActive, pool.getMaxActive());
1206         assertEquals(maxIdle, pool.getMaxIdle());
1207         assertEquals(maxWait, pool.getMaxWait());
1208         assertEquals(GenericKeyedObjectPool.DEFAULT_MIN_IDLE, pool.getMinIdle());
1209         assertEquals(maxTotal, pool.getMaxTotal());
1210         assertEquals(minEvictableIdleTimeMillis,
1211                 pool.getMinEvictableIdleTimeMillis());
1212         assertEquals(numTestsPerEvictionRun,
1213                 pool.getNumTestsPerEvictionRun());
1214         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1215         assertEquals(testOnReturn, pool.getTestOnReturn());
1216         assertEquals(testWhileIdle,
1217                 pool.getTestWhileIdle());
1218         assertEquals(timeBetweenEvictionRunsMillis,
1219                 pool.getTimeBetweenEvictionRunsMillis());
1220         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1221         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1222         
1223         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1224                 maxWait, maxIdle, maxTotal, minIdle, testOnBorrow, testOnReturn,
1225                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1226                 minEvictableIdleTimeMillis, testWhileIdle);
1227         assertEquals(maxActive, pool.getMaxActive());
1228         assertEquals(maxIdle, pool.getMaxIdle());
1229         assertEquals(maxWait, pool.getMaxWait());
1230         assertEquals(minIdle, pool.getMinIdle());
1231         assertEquals(maxTotal, pool.getMaxTotal());
1232         assertEquals(minEvictableIdleTimeMillis,
1233                 pool.getMinEvictableIdleTimeMillis());
1234         assertEquals(numTestsPerEvictionRun,
1235                 pool.getNumTestsPerEvictionRun());
1236         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1237         assertEquals(testOnReturn, pool.getTestOnReturn());
1238         assertEquals(testWhileIdle,
1239                 pool.getTestWhileIdle());
1240         assertEquals(timeBetweenEvictionRunsMillis,
1241                 pool.getTimeBetweenEvictionRunsMillis());
1242         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1243         assertEquals(GenericKeyedObjectPool.DEFAULT_LIFO, pool.getLifo());
1244         
1245         pool = new GenericKeyedObjectPool(null, maxActive, whenExhaustedAction,
1246                 maxWait, maxIdle, maxTotal, minIdle, testOnBorrow, testOnReturn,
1247                 timeBetweenEvictionRunsMillis, numTestsPerEvictionRun,
1248                 minEvictableIdleTimeMillis, testWhileIdle, lifo);
1249         assertEquals(maxActive, pool.getMaxActive());
1250         assertEquals(maxIdle, pool.getMaxIdle());
1251         assertEquals(maxWait, pool.getMaxWait());
1252         assertEquals(minIdle, pool.getMinIdle());
1253         assertEquals(maxTotal, pool.getMaxTotal());
1254         assertEquals(minEvictableIdleTimeMillis,
1255                 pool.getMinEvictableIdleTimeMillis());
1256         assertEquals(numTestsPerEvictionRun,
1257                 pool.getNumTestsPerEvictionRun());
1258         assertEquals(testOnBorrow, pool.getTestOnBorrow());
1259         assertEquals(testOnReturn, pool.getTestOnReturn());
1260         assertEquals(testWhileIdle,
1261                 pool.getTestWhileIdle());
1262         assertEquals(timeBetweenEvictionRunsMillis,
1263                 pool.getTimeBetweenEvictionRunsMillis());
1264         assertEquals(whenExhaustedAction,pool.getWhenExhaustedAction());
1265         assertEquals(lifo, pool.getLifo());  
1266     }
1267     
1268     public void testExceptionOnPassivateDuringReturn() throws Exception {
1269         SimpleFactory factory = new SimpleFactory();        
1270         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1271         Object obj = pool.borrowObject("one");
1272         factory.setThrowExceptionOnPassivate(true);
1273         pool.returnObject("one", obj);
1274         assertEquals(0,pool.getNumIdle());
1275         pool.close();
1276     }
1277     
1278     public void testExceptionOnDestroyDuringBorrow() throws Exception {
1279         SimpleFactory factory = new SimpleFactory(); 
1280         factory.setThrowExceptionOnDestroy(true);
1281         factory.setValidationEnabled(true);
1282         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1283         pool.setTestOnBorrow(true);
1284         pool.borrowObject("one");
1285         factory.setValid(false); // Make validation fail on next borrow attempt
1286         try {
1287             pool.borrowObject("one");
1288             fail("Expecting NoSuchElementException");
1289         } catch (NoSuchElementException ex) {
1290             // expected
1291         }
1292         assertEquals(1, pool.getNumActive("one"));
1293         assertEquals(0, pool.getNumIdle("one"));
1294         assertEquals(1, pool.getNumActive());
1295         assertEquals(0, pool.getNumIdle());
1296     }
1297     
1298     public void testExceptionOnDestroyDuringReturn() throws Exception {
1299         SimpleFactory factory = new SimpleFactory(); 
1300         factory.setThrowExceptionOnDestroy(true);
1301         factory.setValidationEnabled(true);
1302         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1303         pool.setTestOnReturn(true);
1304         Object obj1 = pool.borrowObject("one");
1305         pool.borrowObject("one");
1306         factory.setValid(false); // Make validation fail
1307         pool.returnObject("one", obj1);
1308         assertEquals(1, pool.getNumActive("one"));
1309         assertEquals(0, pool.getNumIdle("one"));
1310         assertEquals(1, pool.getNumActive());
1311         assertEquals(0, pool.getNumIdle());
1312     }
1313     
1314     public void testExceptionOnActivateDuringBorrow() throws Exception {
1315         SimpleFactory factory = new SimpleFactory(); 
1316         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1317         Object obj1 = pool.borrowObject("one");
1318         Object obj2 = pool.borrowObject("one");
1319         pool.returnObject("one", obj1);
1320         pool.returnObject("one", obj2);
1321         factory.setThrowExceptionOnActivate(true);
1322         factory.setEvenValid(false);  
1323         // Activation will now throw every other time
1324         // First attempt throws, but loop continues and second succeeds
1325         Object obj = pool.borrowObject("one");
1326         assertEquals(1, pool.getNumActive("one"));
1327         assertEquals(0, pool.getNumIdle("one"));
1328         assertEquals(1, pool.getNumActive());
1329         assertEquals(0, pool.getNumIdle());
1330         
1331         pool.returnObject("one", obj);
1332         factory.setValid(false);
1333         // Validation will now fail on activation when borrowObject returns
1334         // an idle instance, and then when attempting to create a new instance
1335         try {
1336             pool.borrowObject("one");
1337             fail("Expecting NoSuchElementException");
1338         } catch (NoSuchElementException ex) {
1339             // expected
1340         }
1341         assertEquals(0, pool.getNumActive("one"));
1342         assertEquals(0, pool.getNumIdle("one"));
1343         assertEquals(0, pool.getNumActive());
1344         assertEquals(0, pool.getNumIdle());
1345     }
1346     
1347     public void testBlockedKeyDoesNotBlockPool() throws Exception {
1348         SimpleFactory factory = new SimpleFactory();
1349         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1350         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
1351         pool.setMaxWait(5000);
1352         pool.setMaxActive(1);
1353         pool.setMaxTotal(-1);
1354         pool.borrowObject("one");
1355         long start = System.currentTimeMillis();
1356         // Needs to be in a separate thread as this will block
1357         Runnable simple = new SimpleTestThread(pool, "one");
1358         (new Thread(simple)).start();
1359         // This should be almost instant. If it isn't it means this thread got
1360         // stuck behind the thread created above which is bad.
1361         // Give other thread a chance to start
1362         Thread.sleep(1000);
1363         pool.borrowObject("two");
1364         long end = System.currentTimeMillis();
1365         // If it fails it will be more than 4000ms (5000 less the 1000 sleep)
1366         // If it passes it should be almost instant
1367         // Use 3000ms as the threshold - should avoid timing issues on most
1368         // (all? platforms)
1369         assertTrue ("Elapsed time: "+(end-start)+" should be less than 4000",(end-start) < 4000);
1370         
1371     }
1372 
1373     private static final boolean DISPLAY_THREAD_DETAILS=
1374         Boolean.valueOf(System.getProperty("TestGenericKeyedObjectPool.display.thread.details", "false")).booleanValue();
1375     // To pass this to a Maven test, use:
1376     // mvn test -DargLine="-DTestGenericKeyedObjectPool.display.thread.details=true"
1377     // @see http://jira.codehaus.org/browse/SUREFIRE-121
1378 
1379     /*
1380      * Test multi-threaded pool access.
1381      * Multiple keys, multiple threads, but maxActive only allows half the threads to succeed.
1382      * 
1383      * This test was prompted by Continuum build failures in the Commons DBCP test case:
1384      * TestSharedPoolDataSource.testMultipleThreads2()
1385      * Let's see if the this fails on Continuum too!
1386      */
1387     public void testMaxWaitMultiThreaded() throws Exception {
1388         final long maxWait = 500; // wait for connection
1389         final long holdTime = 2 * maxWait; // how long to hold connection
1390         final int keyCount = 4; // number of different keys
1391         final int threadsPerKey = 5; // number of threads to grab the key initially
1392         SimpleFactory factory = new SimpleFactory();
1393         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1394         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_BLOCK);
1395         pool.setMaxWait(maxWait);
1396         pool.setMaxActive(threadsPerKey);
1397         // Create enough threads so half the threads will have to wait
1398         WaitingTestThread wtt[] = new WaitingTestThread[keyCount * threadsPerKey * 2];
1399         for(int i=0; i < wtt.length; i++){
1400             wtt[i] = new WaitingTestThread(pool,Integer.toString(i % keyCount),holdTime);
1401         }
1402         long origin = System.currentTimeMillis()-1000;
1403         for(int i=0; i < wtt.length; i++){
1404             wtt[i].start();
1405         }
1406         int failed = 0;
1407         for(int i=0; i < wtt.length; i++){
1408             wtt[i].join();
1409             if (wtt[i]._thrown != null){
1410                 failed++;
1411             }
1412         }
1413         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
1414             System.out.println(
1415                     "MaxWait: "+maxWait
1416                     +" HoldTime: "+holdTime
1417                     +" KeyCount: "+keyCount
1418                     +" MaxActive: "+threadsPerKey
1419                     +" Threads: "+wtt.length
1420                     +" Failed: "+failed
1421                     );
1422             for(int i=0; i < wtt.length; i++){
1423                 WaitingTestThread wt = wtt[i];
1424                 System.out.println(
1425                         "Preborrow: "+(wt.preborrow-origin)
1426                         + " Postborrow: "+(wt.postborrow != 0 ? wt.postborrow-origin : -1)
1427                         + " BorrowTime: "+(wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1)
1428                         + " PostReturn: "+(wt.postreturn != 0 ? wt.postreturn-origin : -1)
1429                         + " Ended: "+(wt.ended-origin)
1430                         + " Key: "+(wt._key)
1431                         + " ObjId: "+wt.objectId
1432                         );
1433             }            
1434         }
1435         assertEquals("Expected half the threads to fail",wtt.length/2,failed);
1436     }
1437 
1438     /**
1439      * Test case for POOL-180.
1440      */
1441     public void testMaxActivePerKeyExceeded() {
1442         WaiterFactory factory = new WaiterFactory(0, 20, 0, 0, 0, 0, 8, 5, 0);
1443         pool = new GenericKeyedObjectPool(factory);
1444         pool.setMaxActive(5);
1445         pool.setMaxTotal(8);
1446         pool.setTestOnBorrow(true);
1447         pool.setMaxIdle(5);
1448         pool.setMaxWait(-1);
1449         runTestThreads(20, 300, 250);
1450     }
1451     
1452     /**
1453      * POOL-192
1454      * Verify that clear(key) does not leak capacity due to _numInternalProcessing
1455      * not being decremented.
1456      */
1457     public void testClear() throws Exception {
1458         SimpleFactory factory = new SimpleFactory();
1459         GenericKeyedObjectPool pool = new GenericKeyedObjectPool(factory);
1460         pool.setMaxTotal(2);
1461         pool.setMaxActive(2);
1462         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
1463         pool.addObject("one");
1464         pool.addObject("one");
1465         assertEquals(2, pool.getNumIdle());
1466         pool.clear("one");
1467         assertEquals(0, pool.getNumIdle());
1468         assertEquals(0, pool.getNumIdle("one"));
1469         Object obj1 = pool.borrowObject("one");
1470         Object obj2 = pool.borrowObject("one");
1471         pool.returnObject("one", obj1);
1472         pool.returnObject("one", obj2);
1473         pool.clear();
1474         assertEquals(0, pool.getNumIdle());
1475         assertEquals(0, pool.getNumIdle("one"));
1476         pool.borrowObject("one");
1477         pool.borrowObject("one");
1478         pool.close();
1479     }
1480     
1481     /*
1482      * Very simple test thread that just tries to borrow an object from
1483      * the provided pool with the specified key and returns it
1484      */
1485     static class SimpleTestThread implements Runnable {
1486         private final KeyedObjectPool _pool;
1487         private final String _key;
1488         
1489         public SimpleTestThread(KeyedObjectPool pool, String key) {
1490             _pool = pool;
1491             _key = key;
1492         }
1493 
1494         public void run() {
1495             try {
1496                 Object obj = _pool.borrowObject(_key);
1497                 _pool.returnObject(_key, obj);
1498             } catch (Exception e) {
1499                 // Ignore
1500             }
1501         }
1502     }
1503     
1504     /*
1505      * Very simple test thread that just tries to borrow an object from
1506      * the provided pool with the specified key and returns it after a wait
1507      */
1508     static class WaitingTestThread extends Thread {
1509         private final KeyedObjectPool _pool;
1510         private final String _key;
1511         private final long _pause;
1512         private Throwable _thrown;
1513         
1514         private long preborrow; // just before borrow
1515         private long postborrow; //  borrow returned
1516         private long postreturn; // after object was returned
1517         private long ended;
1518         private String objectId;
1519 
1520         public WaitingTestThread(KeyedObjectPool pool, String key, long pause) {
1521             _pool = pool;
1522             _key = key;
1523             _pause = pause;
1524             _thrown = null;
1525         }
1526 
1527         public void run() {
1528             try {
1529                 preborrow = System.currentTimeMillis();
1530                 Object obj = _pool.borrowObject(_key);
1531                 objectId=obj.toString();
1532                 postborrow = System.currentTimeMillis();
1533                 Thread.sleep(_pause);
1534                 _pool.returnObject(_key, obj);
1535                 postreturn = System.currentTimeMillis();
1536             } catch (Exception e) {
1537                 _thrown = e;
1538             } finally{
1539                 ended = System.currentTimeMillis();
1540             }
1541         }
1542     }
1543     
1544     static class TestThread implements Runnable {
1545         private final java.util.Random _random = new java.util.Random();
1546         
1547         // Thread config items
1548         private final KeyedObjectPool _pool;
1549         private final int _iter;
1550         private final int _delay;
1551 
1552         private volatile boolean _complete = false;
1553         private volatile boolean _failed = false;
1554         private volatile Exception _exception;
1555 
1556         public TestThread(KeyedObjectPool pool) {
1557             this(pool, 100, 50);
1558         }
1559 
1560         public TestThread(KeyedObjectPool pool, int iter) {
1561             this(pool, iter, 50);
1562         }
1563 
1564         public TestThread(KeyedObjectPool pool, int iter, int delay) {
1565             _pool = pool;
1566             _iter = iter;
1567             _delay = delay;
1568         }
1569 
1570         public boolean complete() {
1571             return _complete;
1572         }
1573 
1574         public boolean failed() {
1575             return _failed;
1576         }
1577 
1578         public void run() {
1579             for(int i=0;i<_iter;i++) {
1580                 String key = String.valueOf(_random.nextInt(3));
1581                 try {
1582                     Thread.sleep(_random.nextInt(_delay));
1583                 } catch(InterruptedException e) {
1584                     // ignored
1585                 }
1586                 Object obj = null;
1587                 try {
1588                     obj = _pool.borrowObject(key);
1589                 } catch(Exception e) {
1590                     _exception = e;
1591                     _failed = true;
1592                     _complete = true;
1593                     break;
1594                 }
1595 
1596                 try {
1597                     Thread.sleep(_random.nextInt(_delay));
1598                 } catch(InterruptedException e) {
1599                     // ignored
1600                 }
1601                 try {
1602                     _pool.returnObject(key,obj);
1603                 } catch(Exception e) {
1604                     _exception = e;
1605                     _failed = true;
1606                     _complete = true;
1607                     break;
1608                 }
1609             }
1610             _complete = true;
1611         }
1612     }
1613 
1614     static class SimpleFactory implements KeyedPoolableObjectFactory {
1615         public SimpleFactory() {
1616             this(true);
1617         }
1618         public SimpleFactory(boolean valid) {
1619             this.valid = valid;
1620         }
1621         public Object makeObject(Object key) {
1622             synchronized(this) {
1623                 activeCount++;
1624                 if (activeCount > maxActive) {
1625                     throw new IllegalStateException(
1626                         "Too many active instances: " + activeCount);
1627                 }
1628             }
1629             return String.valueOf(key) + String.valueOf(counter++);
1630         }
1631         public void destroyObject(Object key, Object obj) throws Exception {
1632             doWait(destroyLatency);
1633             synchronized(this) {
1634                 activeCount--;
1635             }
1636             if (exceptionOnDestroy) {
1637                 throw new Exception();
1638             }
1639         }
1640         public boolean validateObject(Object key, Object obj) {
1641             if (enableValidation) { 
1642                 return validateCounter++%2 == 0 ? evenValid : oddValid; 
1643             } else {
1644                 return valid;
1645             }
1646         }
1647         public void activateObject(Object key, Object obj) throws Exception {
1648             if (exceptionOnActivate) {
1649                 if (!(validateCounter++%2 == 0 ? evenValid : oddValid)) {
1650                     throw new Exception();
1651                 }
1652             }
1653         }
1654         public void passivateObject(Object key, Object obj) throws Exception {
1655             if (exceptionOnPassivate) {
1656                 throw new Exception();
1657             }
1658         }
1659         
1660         public void setMaxActive(int maxActive) {
1661             this.maxActive = maxActive;
1662         }
1663         public void setDestroyLatency(long destroyLatency) {
1664             this.destroyLatency = destroyLatency;
1665         }
1666         public void setValidationEnabled(boolean b) {
1667             enableValidation = b;
1668         }
1669         void setEvenValid(boolean valid) {
1670             evenValid = valid;
1671         }
1672         void setValid(boolean valid) {
1673             evenValid = valid;
1674             oddValid = valid;
1675         }
1676         
1677         public void setThrowExceptionOnActivate(boolean b) {
1678             exceptionOnActivate = b;
1679         }
1680         
1681         public void setThrowExceptionOnDestroy(boolean b) {
1682             exceptionOnDestroy = b;
1683         }
1684         
1685         public void setThrowExceptionOnPassivate(boolean b) {
1686             exceptionOnPassivate = b;
1687         }
1688         
1689         int counter = 0;
1690         boolean valid;
1691         
1692         int activeCount = 0;
1693         int validateCounter = 0;
1694         boolean evenValid = true;
1695         boolean oddValid = true;
1696         boolean enableValidation = false;
1697         long destroyLatency = 0;
1698         int maxActive = Integer.MAX_VALUE;
1699         boolean exceptionOnPassivate = false;
1700         boolean exceptionOnActivate = false;
1701         boolean exceptionOnDestroy = false;
1702         
1703         private void doWait(long latency) {
1704             try {
1705                 Thread.sleep(latency);
1706             } catch (InterruptedException ex) {
1707                 // ignore
1708             }
1709         }
1710     }
1711 
1712     protected boolean isLifo() {
1713         return true;
1714     }
1715 
1716     protected boolean isFifo() {
1717         return false;
1718     }
1719 
1720     private String getExceptionTrace(Throwable t){
1721         StringWriter sw = new StringWriter();
1722         t.printStackTrace(new PrintWriter(sw));
1723         return sw.toString();
1724     }
1725     
1726     private String formatSettings(String title, String s, int i, String s0, boolean b0, String s1, int i1, String s2, int i2, String s3, int i3,
1727             String s4, int i4, String s5, int i5, String s6, int i6, int zeroLength, int oneLength, int twoLength){
1728         StringBuffer sb = new StringBuffer(80);
1729         sb.append(title).append(' ');
1730         sb.append(s).append('=').append(i).append(' ');
1731         sb.append(s0).append('=').append(b0).append(' ');
1732         sb.append(s1).append('=').append(i1).append(' ');
1733         sb.append(s2).append('=').append(i2).append(' ');
1734         sb.append(s3).append('=').append(i3).append(' ');
1735         sb.append(s4).append('=').append(i4).append(' ');
1736         sb.append(s5).append('=').append(i5).append(' ');
1737         sb.append(s6).append('=').append(i6).append(' ');
1738         sb.append("Lengths=").append(zeroLength).append(',').append(oneLength).append(',').append(twoLength).append(' ');
1739         return sb.toString();
1740     }
1741     
1742 }
1743 
1744