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