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