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