1   /*
2    * Copyright 1999-2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.pool.impl;
18  
19  import java.util.HashMap;
20  import java.util.NoSuchElementException;
21  
22  import junit.framework.Test;
23  import junit.framework.TestSuite;
24  
25  import org.apache.commons.pool.KeyedObjectPool;
26  import org.apache.commons.pool.KeyedPoolableObjectFactory;
27  import org.apache.commons.pool.TestKeyedObjectPool;
28  
29  /***
30   * @author Rodney Waldhoff
31   * @version $Revision: 383290 $ $Date: 2006-03-05 02:00:15 -0500 (Sun, 05 Mar 2006) $
32   */
33  public class TestGenericKeyedObjectPool extends TestKeyedObjectPool {
34      public TestGenericKeyedObjectPool(String testName) {
35          super(testName);
36      }
37  
38      public static Test suite() {
39          return new TestSuite(TestGenericKeyedObjectPool.class);
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 Object getNthObject(Object key, int n) {
67          return String.valueOf(key) + String.valueOf(n);
68      }
69  
70      protected Object makeKey(int n) {
71          return String.valueOf(n);
72      }
73  
74      private GenericKeyedObjectPool pool = null;
75  
76      public void setUp() throws Exception {
77          super.setUp();
78          pool = new GenericKeyedObjectPool(new SimpleFactory());
79      }
80  
81      public void tearDown() throws Exception {
82          super.tearDown();
83          pool.close();
84          pool = null;
85      }
86  
87      public void testWithInitiallyInvalid() throws Exception {
88          GenericKeyedObjectPool pool = new GenericKeyedObjectPool(new SimpleFactory(false));
89          pool.setTestOnBorrow(true);
90          try {
91              pool.borrowObject("xyzzy");
92              fail("Expected NoSuchElementException");
93          } catch(NoSuchElementException e) {
94              // expected
95          }
96      }
97  
98      public void testNegativeMaxActive() throws Exception {
99          pool.setMaxActive(-1);
100         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
101         Object obj = pool.borrowObject("");
102         assertEquals("0",obj);
103         pool.returnObject("",obj);
104     }
105 
106     public void testNumActiveNumIdle2() throws Exception {
107         assertEquals(0,pool.getNumActive());
108         assertEquals(0,pool.getNumIdle());
109         assertEquals(0,pool.getNumActive("A"));
110         assertEquals(0,pool.getNumIdle("A"));
111         assertEquals(0,pool.getNumActive("B"));
112         assertEquals(0,pool.getNumIdle("B"));
113 
114         Object objA0 = pool.borrowObject("A");
115         Object objB0 = pool.borrowObject("B");
116 
117         assertEquals(2,pool.getNumActive());
118         assertEquals(0,pool.getNumIdle());
119         assertEquals(1,pool.getNumActive("A"));
120         assertEquals(0,pool.getNumIdle("A"));
121         assertEquals(1,pool.getNumActive("B"));
122         assertEquals(0,pool.getNumIdle("B"));
123 
124         Object objA1 = pool.borrowObject("A");
125         Object objB1 = pool.borrowObject("B");
126 
127         assertEquals(4,pool.getNumActive());
128         assertEquals(0,pool.getNumIdle());
129         assertEquals(2,pool.getNumActive("A"));
130         assertEquals(0,pool.getNumIdle("A"));
131         assertEquals(2,pool.getNumActive("B"));
132         assertEquals(0,pool.getNumIdle("B"));
133 
134         pool.returnObject("A",objA0);
135         pool.returnObject("B",objB0);
136 
137         assertEquals(2,pool.getNumActive());
138         assertEquals(2,pool.getNumIdle());
139         assertEquals(1,pool.getNumActive("A"));
140         assertEquals(1,pool.getNumIdle("A"));
141         assertEquals(1,pool.getNumActive("B"));
142         assertEquals(1,pool.getNumIdle("B"));
143 
144         pool.returnObject("A",objA1);
145         pool.returnObject("B",objB1);
146 
147         assertEquals(0,pool.getNumActive());
148         assertEquals(4,pool.getNumIdle());
149         assertEquals(0,pool.getNumActive("A"));
150         assertEquals(2,pool.getNumIdle("A"));
151         assertEquals(0,pool.getNumActive("B"));
152         assertEquals(2,pool.getNumIdle("B"));
153     }
154 
155     public void testMaxIdle() throws Exception {
156         pool.setMaxActive(100);
157         pool.setMaxIdle(8);
158         Object[] active = new Object[100];
159         for(int i=0;i<100;i++) {
160             active[i] = pool.borrowObject("");
161         }
162         assertEquals(100,pool.getNumActive(""));
163         assertEquals(0,pool.getNumIdle(""));
164         for(int i=0;i<100;i++) {
165             pool.returnObject("",active[i]);
166             assertEquals(99 - i,pool.getNumActive(""));
167             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle(""));
168         }
169     }
170 
171     public void testMaxActive() throws Exception {
172         pool.setMaxActive(3);
173         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
174 
175         pool.borrowObject("");
176         pool.borrowObject("");
177         pool.borrowObject("");
178         try {
179             pool.borrowObject("");
180             fail("Expected NoSuchElementException");
181         } catch(NoSuchElementException e) {
182             // expected
183         }
184     }
185 
186     public void testMaxActiveZero() throws Exception {
187         pool.setMaxActive(0);
188         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
189 
190         try {
191             pool.borrowObject("a");
192             fail("Expected NoSuchElementException");
193         } catch(NoSuchElementException e) {
194             // expected
195         }
196     }
197 
198     public void testMaxTotal() throws Exception {
199         pool.setMaxActive(2);
200         pool.setMaxTotal(3);
201         pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
202 
203         Object o1 = pool.borrowObject("a");
204         assertNotNull(o1);
205         Object o2 = pool.borrowObject("a");
206         assertNotNull(o2);
207         Object o3 = pool.borrowObject("b");
208         assertNotNull(o3);
209         try {
210             pool.borrowObject("c");
211             fail("Expected NoSuchElementException");
212         } catch(NoSuchElementException e) {
213             // expected
214         }
215 
216         assertEquals(0, pool.getNumIdle());
217 
218         pool.returnObject("b", o3);
219         assertEquals(1, pool.getNumIdle());
220         assertEquals(1, pool.getNumIdle("b"));
221 
222         Object o4 = pool.borrowObject("b");
223         assertNotNull(o4);
224         assertEquals(0, pool.getNumIdle());
225         assertEquals(0, pool.getNumIdle("b"));
226     }
227 
228     public void testMaxTotalZero() throws Exception {
229         pool.setMaxTotal(0);
230         pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_FAIL);
231 
232         try {
233             pool.borrowObject("a");
234             fail("Expected NoSuchElementException");
235         } catch(NoSuchElementException e) {
236             // expected
237         }
238     }
239 
240     public void testMaxTotalLRU() throws Exception {
241         pool.setMaxActive(2);
242         pool.setMaxTotal(3);
243 //        pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW);
244 
245         Object o1 = pool.borrowObject("a");
246         assertNotNull(o1);
247         pool.returnObject("a", o1);
248         Thread.sleep(10);
249 
250         Object o2 = pool.borrowObject("b");
251         assertNotNull(o2);
252         pool.returnObject("b", o2);
253         Thread.sleep(10);
254 
255         Object o3 = pool.borrowObject("c");
256         assertNotNull(o3);
257         pool.returnObject("c", o3);
258         Thread.sleep(10);
259 
260         Object o4 = pool.borrowObject("a");
261         assertNotNull(o4);
262         pool.returnObject("a", o4);
263         Thread.sleep(10);
264 
265         assertSame(o1, o4);
266 
267         // this should cause b to be bumped out of the pool
268         Object o5 = pool.borrowObject("d");
269         assertNotNull(o5);
270         pool.returnObject("d", o5);
271         Thread.sleep(10);
272 
273         // now re-request b, we should get a different object because it should
274         // have been expelled from pool (was oldest because a was requested after b)
275         Object o6 = pool.borrowObject("b");
276         assertNotNull(o6);
277         pool.returnObject("b", o6);
278 
279         assertNotSame(o1, o6);
280 
281         // second a is still in there
282         Object o7 = pool.borrowObject("a");
283         assertNotNull(o7);
284         pool.returnObject("a", o7);
285 
286         assertSame(o4, o7);
287     }
288 
289     public void testSettersAndGetters() throws Exception {
290         GenericKeyedObjectPool pool = new GenericKeyedObjectPool();
291         {
292             pool.setFactory(new SimpleFactory());
293         }
294         {
295             pool.setMaxActive(123);
296             assertEquals(123,pool.getMaxActive());
297         }
298         {
299             pool.setMaxIdle(12);
300             assertEquals(12,pool.getMaxIdle());
301         }
302         {
303             pool.setMaxWait(1234L);
304             assertEquals(1234L,pool.getMaxWait());
305         }
306         {
307             pool.setMinEvictableIdleTimeMillis(12345L);
308             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
309         }
310         {
311             pool.setNumTestsPerEvictionRun(11);
312             assertEquals(11,pool.getNumTestsPerEvictionRun());
313         }
314         {
315             pool.setTestOnBorrow(true);
316             assertTrue(pool.getTestOnBorrow());
317             pool.setTestOnBorrow(false);
318             assertTrue(!pool.getTestOnBorrow());
319         }
320         {
321             pool.setTestOnReturn(true);
322             assertTrue(pool.getTestOnReturn());
323             pool.setTestOnReturn(false);
324             assertTrue(!pool.getTestOnReturn());
325         }
326         {
327             pool.setTestWhileIdle(true);
328             assertTrue(pool.getTestWhileIdle());
329             pool.setTestWhileIdle(false);
330             assertTrue(!pool.getTestWhileIdle());
331         }
332         {
333             pool.setTimeBetweenEvictionRunsMillis(11235L);
334             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
335         }
336         {
337             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_BLOCK);
338             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK,pool.getWhenExhaustedAction());
339             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_FAIL);
340             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_FAIL,pool.getWhenExhaustedAction());
341             pool.setWhenExhaustedAction(GenericKeyedObjectPool.WHEN_EXHAUSTED_GROW);
342             assertEquals(GenericObjectPool.WHEN_EXHAUSTED_GROW,pool.getWhenExhaustedAction());
343         }
344     }
345 
346     public void testEviction() throws Exception {
347         pool.setMaxIdle(500);
348         pool.setMaxActive(500);
349         pool.setNumTestsPerEvictionRun(100);
350         pool.setMinEvictableIdleTimeMillis(250L);
351         pool.setTimeBetweenEvictionRunsMillis(500L);
352 
353         Object[] active = new Object[500];
354         for(int i=0;i<500;i++) {
355             active[i] = pool.borrowObject("");
356         }
357         for(int i=0;i<500;i++) {
358             pool.returnObject("",active[i]);
359         }
360 
361         try { Thread.sleep(1000L); } catch(Exception e) { }
362         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 500);
363         try { Thread.sleep(600L); } catch(Exception e) { }
364         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 400);
365         try { Thread.sleep(600L); } catch(Exception e) { }
366         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 300);
367         try { Thread.sleep(600L); } catch(Exception e) { }
368         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 200);
369         try { Thread.sleep(600L); } catch(Exception e) { }
370         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 100);
371         try { Thread.sleep(600L); } catch(Exception e) { }
372         assertEquals("Should be zero idle, found " + pool.getNumIdle(""),0,pool.getNumIdle(""));
373 
374         for(int i=0;i<500;i++) {
375             active[i] = pool.borrowObject("");
376         }
377         for(int i=0;i<500;i++) {
378             pool.returnObject("",active[i]);
379         }
380 
381         try { Thread.sleep(1000L); } catch(Exception e) { }
382         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 500);
383         try { Thread.sleep(600L); } catch(Exception e) { }
384         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 400);
385         try { Thread.sleep(600L); } catch(Exception e) { }
386         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 300);
387         try { Thread.sleep(600L); } catch(Exception e) { }
388         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 200);
389         try { Thread.sleep(600L); } catch(Exception e) { }
390         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(""),pool.getNumIdle("") < 100);
391         try { Thread.sleep(600L); } catch(Exception e) { }
392         assertEquals("Should be zero idle, found " + pool.getNumIdle(""),0,pool.getNumIdle(""));
393     }
394 
395     public void testEviction2() throws Exception {
396         pool.setMaxIdle(500);
397         pool.setMaxActive(500);
398         pool.setNumTestsPerEvictionRun(100);
399         pool.setMinEvictableIdleTimeMillis(500L);
400         pool.setTimeBetweenEvictionRunsMillis(500L);
401 
402         Object[] active = new Object[500];
403         Object[] active2 = new Object[500];
404         for(int i=0;i<500;i++) {
405             active[i] = pool.borrowObject("");
406             active2[i] = pool.borrowObject("2");
407         }
408         for(int i=0;i<500;i++) {
409             pool.returnObject("",active[i]);
410             pool.returnObject("2",active2[i]);
411         }
412 
413         try { Thread.sleep(1000L); } catch(Exception e) { }
414         assertTrue("Should be less than 1000 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 1000);
415         try { Thread.sleep(600L); } catch(Exception e) { }
416         assertTrue("Should be less than 900 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 900);
417         try { Thread.sleep(600L); } catch(Exception e) { }
418         assertTrue("Should be less than 800 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 800);
419         try { Thread.sleep(600L); } catch(Exception e) { }
420         assertTrue("Should be less than 700 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 700);
421         try { Thread.sleep(600L); } catch(Exception e) { }
422         assertTrue("Should be less than 600 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 600);
423         try { Thread.sleep(600L); } catch(Exception e) { }
424         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
425         try { Thread.sleep(600L); } catch(Exception e) { }
426         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
427         try { Thread.sleep(600L); } catch(Exception e) { }
428         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
429         try { Thread.sleep(600L); } catch(Exception e) { }
430         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
431         try { Thread.sleep(600L); } catch(Exception e) { }
432         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
433         try { Thread.sleep(600L); } catch(Exception e) { }
434         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
435     }
436 
437     public void testThreaded1() throws Exception {
438         pool.setMaxActive(15);
439         pool.setMaxIdle(15);
440         pool.setMaxWait(1000L);
441         TestThread[] threads = new TestThread[20];
442         for(int i=0;i<20;i++) {
443             threads[i] = new TestThread(pool,100,50);
444             Thread t = new Thread(threads[i]);
445             t.start();
446         }
447         for(int i=0;i<20;i++) {
448             while(!(threads[i]).complete()) {
449                 try {
450                     Thread.sleep(500L);
451                 } catch(Exception e) {
452                     // ignored
453                 }
454             }
455             if(threads[i].failed()) {
456                 fail();
457             }
458         }
459     }
460 
461     public void testMinIdle() throws Exception {
462         pool.setMaxIdle(500);
463         pool.setMinIdle(5);
464         pool.setMaxActive(10);
465         pool.setNumTestsPerEvictionRun(0);
466         pool.setMinEvictableIdleTimeMillis(50L);
467         pool.setTimeBetweenEvictionRunsMillis(100L);
468         pool.setTestWhileIdle(true);
469 
470 
471         //Generate a random key
472         String key = "A";
473 
474         pool.preparePool(key, true);
475 
476         try { Thread.sleep(150L); } catch(Exception e) { }
477         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
478 
479         Object[] active = new Object[5];
480         active[0] = pool.borrowObject(key);
481 
482         try { Thread.sleep(150L); } catch(Exception e) { }
483         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
484 
485         for(int i=1 ; i<5 ; i++) {
486             active[i] = pool.borrowObject(key);
487         }
488 
489         try { Thread.sleep(150L); } catch(Exception e) { }
490         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
491 
492         for(int i=0 ; i<5 ; i++) {
493             pool.returnObject(key, active[i]);
494         }
495 
496         try { Thread.sleep(150L); } catch(Exception e) { }
497         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
498     }
499 
500     public void testMinIdleMaxActive() throws Exception {
501         pool.setMaxIdle(500);
502         pool.setMinIdle(5);
503         pool.setMaxActive(10);
504         pool.setNumTestsPerEvictionRun(0);
505         pool.setMinEvictableIdleTimeMillis(50L);
506         pool.setTimeBetweenEvictionRunsMillis(100L);
507         pool.setTestWhileIdle(true);
508 
509         String key = "A";
510 
511         pool.preparePool(key, true);
512 
513         try { Thread.sleep(150L); } catch(Exception e) { }
514         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
515 
516         Object[] active = new Object[10];
517 
518         try { Thread.sleep(150L); } catch(Exception e) { }
519         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
520 
521         for(int i=0 ; i<5 ; i++) {
522             active[i] = pool.borrowObject(key);
523         }
524 
525         try { Thread.sleep(150L); } catch(Exception e) { }
526         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
527 
528         for(int i=0 ; i<5 ; i++) {
529             pool.returnObject(key, active[i]);
530         }
531 
532         try { Thread.sleep(150L); } catch(Exception e) { }
533         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
534 
535         for(int i=0 ; i<10 ; i++) {
536             active[i] = pool.borrowObject(key);
537         }
538 
539         try { Thread.sleep(150L); } catch(Exception e) { }
540         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
541 
542         for(int i=0 ; i<10 ; i++) {
543             pool.returnObject(key, active[i]);
544         }
545 
546         try { Thread.sleep(150L); } catch(Exception e) { }
547         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
548     }
549     
550     public void testMinIdleNoPopulateImmediately() 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(1000L);
557         pool.setTestWhileIdle(true);
558 
559 
560         //Generate a random key
561         String key = "A";
562         
563         pool.preparePool(key, false);
564         
565         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
566         
567         try { Thread.sleep(1500L); } catch(Exception e) { }
568         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
569     }
570     
571     public void testMinIdleNoPreparePool() throws Exception {
572         pool.setMaxIdle(500);
573         pool.setMinIdle(5);
574         pool.setMaxActive(10);
575         pool.setNumTestsPerEvictionRun(0);
576         pool.setMinEvictableIdleTimeMillis(50L);
577         pool.setTimeBetweenEvictionRunsMillis(100L);
578         pool.setTestWhileIdle(true);
579 
580 
581         //Generate a random key
582         String key = "A";
583 
584         try { Thread.sleep(150L); } catch(Exception e) { }
585         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
586 
587         Object active = pool.borrowObject(key);
588         assertNotNull(active);
589 
590         try { Thread.sleep(150L); } catch(Exception e) { }
591         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
592     }
593     
594     public void testFIFO() throws Exception {
595         final Object key = "key";
596         pool.addObject(key); // "key0"
597         pool.addObject(key); // "key1"
598         pool.addObject(key); // "key2"
599         assertEquals("Oldest", "key0", pool.borrowObject(key));
600         assertEquals("Middle", "key1", pool.borrowObject(key));
601         assertEquals("Youngest", "key2", pool.borrowObject(key));
602         assertEquals("new-3", "key3", pool.borrowObject(key));
603         pool.returnObject(key, "r");
604         assertEquals("returned", "r", pool.borrowObject(key));
605         assertEquals("new-4", "key4", pool.borrowObject(key));
606     }
607 
608     class TestThread implements Runnable {
609         java.util.Random _random = new java.util.Random();
610         KeyedObjectPool _pool = null;
611         boolean _complete = false;
612         boolean _failed = false;
613         int _iter = 100;
614         int _delay = 50;
615 
616         public TestThread(KeyedObjectPool pool) {
617             _pool = pool;
618         }
619 
620         public TestThread(KeyedObjectPool pool, int iter) {
621             _pool = pool;
622             _iter = iter;
623         }
624 
625         public TestThread(KeyedObjectPool pool, int iter, int delay) {
626             _pool = pool;
627             _iter = iter;
628             _delay = delay;
629         }
630 
631         public boolean complete() {
632             return _complete;
633         }
634 
635         public boolean failed() {
636             return _failed;
637         }
638 
639         public void run() {
640             for(int i=0;i<_iter;i++) {
641                 String key = String.valueOf(_random.nextInt(3));
642                 try {
643                     Thread.sleep((long)_random.nextInt(_delay));
644                 } catch(Exception e) {
645                     // ignored
646                 }
647                 Object obj = null;
648                 try {
649                     obj = _pool.borrowObject(key);
650                 } catch(Exception e) {
651                     _failed = true;
652                     _complete = true;
653                     break;
654                 }
655 
656                 try {
657                     Thread.sleep((long)_random.nextInt(_delay));
658                 } catch(Exception e) {
659                     // ignored
660                 }
661                 try {
662                     _pool.returnObject(key,obj);
663                 } catch(Exception e) {
664                     _failed = true;
665                     _complete = true;
666                     break;
667                 }
668             }
669             _complete = true;
670         }
671     }
672 
673     static class SimpleFactory implements KeyedPoolableObjectFactory {
674         public SimpleFactory() {
675             this(true);
676         }
677         public SimpleFactory(boolean valid) {
678             this.valid = valid;
679         }
680         public Object makeObject(Object key) { return String.valueOf(key) + String.valueOf(counter++); }
681         public void destroyObject(Object key, Object obj) { }
682         public boolean validateObject(Object key, Object obj) { return valid; }
683         public void activateObject(Object key, Object obj) { }
684         public void passivateObject(Object key, Object obj) { }
685         int counter = 0;
686         boolean valid;
687     }
688 
689     protected boolean isLifo() {
690         return false;
691     }
692 
693     protected boolean isFifo() {
694         return true;
695     }
696 
697 }
698 
699