You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@commons.apache.org by James Leskovar <JL...@telecomsys.com> on 2014/06/19 01:07:44 UTC

Multiplexed connections in commons pool

Hi there,

I have an application that needs to perform connection pooling, with the proviso that it's okay - and actually preferable - for more than one client to checkout and use the same connection object from the pool. Ideally, I would also like to limit the number of concurrent clients that are using a single connection object. I'm wondering what the best way to do this is. As a quick and dirty option, I suppose I could basically have my PooledObjectFactory return the same objects from makeObject(), and manually keep track of objects from inside my implementation. Thoughts?

Cheers,
James Leskovar
Software Engineer, Location Platforms
TeleCommunication Systems, Inc.

[ Address : TCS, iC Enterprise 1, Innovation Campus, Squires Way, Nth Wollongong, NSW, 2500, Australia ]
[ Tel : +61 2 4221 2940 ] [ Fax : +61 2 4221 2901 ]
[ Email : James.Leskovar@telecomsys.com<ma...@telecomsys.com> ]
[TCS]<http://www.telecomsys.com/default.aspx>[Facebook]<https://www.facebook.com/pages/TCS/340389379402958>[Twitter]<https://twitter.com/TeleComSys>[LinkedIn]<http://www.linkedin.com/company/telecommunication-systems>


CONFIDENTIALITY NOTICE: The information contained in this message may be privileged and/or confidential. If you are not the intended recipient, or responsible for delivering this message to the intended recipient, any review, forwarding, dissemination, distribution or copying of this communication or any attachment(s) is strictly prohibited. If you have received this message in error, please notify the sender immediately, and delete it and all attachments from your computer and network.

RE: Multiplexed connections in commons pool

Posted by James Leskovar <JL...@telecomsys.com>.
Hi Martin,

Agreed that care must be taken if multiplexing JDBC connections might be tricky. My use cases are mainly for non-DB related connections (and borderline esoteric ;) - i.e. tunneling RMI over SSH, accessing remote Corba services, etc..

Cheers,
James

-----Original Message-----
From: Martin Gainty [mailto:mgainty@hotmail.com] 
Sent: Thursday, 19 June 2014 8:32 PM
To: Commons Users List
Subject: RE: Multiplexed connections in commons pool




> From: JLeskovar@telecomsys.com
> To: user@commons.apache.org
> Subject: RE: Multiplexed connections in commons pool
> Date: Thu, 19 Jun 2014 00:29:08 +0000
> 
> Hi Martin,
> 
> Thanks for the unit test - I'll check it out.
> 
> > Not sure of the meaning you are inferring with 'multiplexed'
> 
> I'm basically after having multiple calls to borrowObject<T>() return the same object - up to a limit - so that multiple clients can concurrently perform operations on the one connection object. So something like:
> 
> borrowObject() call #1 => returns object 1
> borrowObject() call #2 => returns object 1
> borrowObject() call #3 => returns object 1
MG>OK for read-only cursor
> borrowObject() call #4 => returns object 2
> borrowObject() call #5 => returns object 2
> borrowObject() call #6 => returns object 2
MG>Ok for read-only cursor

MG>Be careful of consequent requests with the same old cursor which doesnt refresh cursor buffer after COMMITS/ROLLBACKS
MG>with that same old cursor
MG>If you are doing any DML (update/insert/delete) operations I would close the connection & grab a new connection each time
> 
> etc..
> 
> Basically, I don't want to have too many open connections to a given remote service, and instead have just a few connections that multiple clients can use - i.e. have a 100 clients borrowObject()'ing over a limited number of connections.
> 
> Cheers,
> James
> 
> 
> -----Original Message-----
> From: Martin Gainty [mailto:mgainty@hotmail.com] 
> Sent: Thursday, 19 June 2014 10:14 AM
> To: Commons Users List
> Subject: RE: Multiplexed connections in commons pool
> 
> James-
> There is a nice test-case in 2.2 apache-commons that covers (Max-timeout-per-connection) and max-connections you are seeking:
> /*
>  * Licensed to the Apache Software Foundation (ASF) under one or more
>  * contributor license agreements.  See the NOTICE file distributed with
>  * this work for additional information regarding copyright ownership.
>  * The ASF licenses this file to You under the Apache License, Version 2.0
>  * (the "License"); you may not use this file except in compliance with
>  * the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing, software
>  * distributed under the License is distributed on an "AS IS" BASIS,
>  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  * See the License for the specific language governing permissions and
>  * limitations under the License.
>  */
> 
> package org.apache.commons.pool2.impl;
> 
> import static org.junit.Assert.assertEquals;
> import static org.junit.Assert.assertFalse;
> import static org.junit.Assert.assertNotNull;
> import static org.junit.Assert.assertNull;
> import static org.junit.Assert.assertTrue;
> import static org.junit.Assert.fail;
> 
> import java.lang.management.ManagementFactory;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.NoSuchElementException;
> import java.util.Random;
> import java.util.Set;
> import java.util.concurrent.atomic.AtomicInteger;
> 
> import javax.management.MBeanServer;
> import javax.management.ObjectName;
> 
> import org.apache.commons.pool2.BasePooledObjectFactory;
> import org.apache.commons.pool2.ObjectPool;
> import org.apache.commons.pool2.PoolUtils;
> import org.apache.commons.pool2.PooledObject;
> import org.apache.commons.pool2.PooledObjectFactory;
> import org.apache.commons.pool2.SwallowedExceptionListener;
> import org.apache.commons.pool2.TestBaseObjectPool;
> import org.apache.commons.pool2.VisitTracker;
> import org.apache.commons.pool2.VisitTrackerFactory;
> import org.junit.After;
> import org.junit.Assert;
> import org.junit.Before;
> import org.junit.Test;
> 
> /**
>  * @version $Revision: 1569016 $
>  */
> public class TestGenericObjectPool extends TestBaseObjectPool {
> 
>     @Override
>     protected ObjectPool<String> makeEmptyPool(int mincap) {
>        GenericObjectPool<String> mtPool =
>                new GenericObjectPool<String>(new SimpleFactory());
>        mtPool.setMaxTotal(mincap);
>        mtPool.setMaxIdle(mincap);
>        return mtPool;
>     }
> 
>     @Override
>     protected ObjectPool<Object> makeEmptyPool(
>             final PooledObjectFactory<Object> fac) {
>         return new GenericObjectPool<Object>(fac);
>     }
> 
>     @Override
>     protected Object getNthObject(int n) {
>         return String.valueOf(n);
>     }
> 
>     @Before
>     public void setUp() throws Exception {
>         factory = new SimpleFactory();
>         pool = new GenericObjectPool<String>(factory);
>     }
> 
>     @After
>     public void tearDown() throws Exception {
>         String poolName = pool.getJmxName().toString();
>         pool.clear();
>         pool.close();
>         pool = null;
>         factory = null;
> 
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(new ObjectName(
>                 "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
>         // There should be no registered pools at this point
>         int registeredPoolCount = result.size();
>         StringBuilder msg = new StringBuilder("Current pool is: ");
>         msg.append(poolName);
>         msg.append("  Still open pools are: ");
>         for (ObjectName name : result) {
>             // Clean these up ready for the next test
>             msg.append(name.toString());
>             msg.append(" created via\n");
>             msg.append(mbs.getAttribute(name, "CreationStackTrace"));
>             msg.append('\n');
>             mbs.unregisterMBean(name);
>         }
>         Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
>     }
> 
>     @Test(expected=IllegalArgumentException.class)
>     public void testConstructorNullFactory() {
>         // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
>         assertNotNull(new GenericObjectPool<String>(null));
>         // TODO this currently causes tearDown to report an error
>         // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
>     }
> 
>     @Test(timeout=60000)
>     public void testConstructors() throws Exception {
> 
>         // Make constructor arguments all different from defaults
>         int minIdle = 2;
>         long maxWait = 3;
>         int maxIdle = 4;
>         int maxTotal = 5;
>         long minEvictableIdleTimeMillis = 6;
>         int numTestsPerEvictionRun = 7;
>         boolean testOnBorrow = true;
>         boolean testOnReturn = true;
>         boolean testWhileIdle = true;
>         long timeBetweenEvictionRunsMillis = 8;
>         boolean blockWhenExhausted = false;
>         boolean lifo = false;
>         PooledObjectFactory<Object> dummyFactory = new DummyFactory();
>         GenericObjectPool<Object> dummyPool =
>                 new GenericObjectPool<Object>(dummyFactory);
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
>                 dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
>                 Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
> 
>         GenericObjectPoolConfig config =
>                 new GenericObjectPoolConfig();
>         config.setLifo(lifo);
>         config.setMaxIdle(maxIdle);
>         config.setMinIdle(minIdle);
>         config.setMaxTotal(maxTotal);
>         config.setMaxWaitMillis(maxWait);
>         config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
>         config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
>         config.setTestOnBorrow(testOnBorrow);
>         config.setTestOnReturn(testOnReturn);
>         config.setTestWhileIdle(testWhileIdle);
>         config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
>         config.setBlockWhenExhausted(blockWhenExhausted);
>         dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
>         assertEquals(maxIdle, dummyPool.getMaxIdle());
>         assertEquals(maxWait, dummyPool.getMaxWaitMillis());
>         assertEquals(minIdle, dummyPool.getMinIdle());
>         assertEquals(maxTotal, dummyPool.getMaxTotal());
>         assertEquals(minEvictableIdleTimeMillis,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(testOnBorrow),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(testOnReturn),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(testWhileIdle),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(timeBetweenEvictionRunsMillis,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(blockWhenExhausted),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedFail() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(false);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumIdle());
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlock() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(10L);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockInterupt() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         String obj1 = pool.borrowObject();
> 
>         // Make sure on object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>         wtt.interrupt();
> 
>         // Give interupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
> 
>         // Return object to the pool
>         pool.returnObject(obj1);
> 
>         // Bug POOL-162 - check there is now an object in the pool
>         pool.setMaxWaitMillis(10L);
>         String obj2 = null;
>         try {
>              obj2 = pool.borrowObject();
>             assertNotNull(obj2);
>         } catch(NoSuchElementException e) {
>             // Not expected
>             fail("NoSuchElementException not expected");
>         }
>         pool.returnObject(obj2);
>         pool.close();
> 
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictWhileEmpty() throws Exception {
>         pool.evict();
>         pool.evict();
>         pool.close();
>     }
> 
>     /**
>      * Tests addObject contention between ensureMinIdle triggered by
>      * the Evictor with minIdle &gt; 0 and borrowObject.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictAddObjects() throws Exception {
>         factory.setMakeLatency(300);
>         factory.setMaxTotal(2);
>         pool.setMaxTotal(2);
>         pool.setMinIdle(1);
>         pool.borrowObject(); // numActive = 1, numIdle = 0
>         // Create a test thread that will run once and try a borrow after
>         // 150ms fixed delay
>         TestThread borrower = new TestThread(pool, 1, 150, false);
>         Thread borrowerThread = new Thread(borrower);
>         // Set evictor to run in 100 ms - will create idle instance
>         pool.setTimeBetweenEvictionRunsMillis(100);
>         borrowerThread.start();  // Off to the races
>         borrowerThread.join();
>         assertTrue(!borrower.failed());
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictLIFO() throws Exception {
>         checkEvict(true);
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictFIFO() throws Exception {
>         checkEvict(false);
>     }
> 
>     private void checkEvict(boolean lifo) throws Exception {
>         // yea this is hairy but it tests all the code paths in GOP.evict()
>         pool.setSoftMinEvictableIdleTimeMillis(10);
>         pool.setMinIdle(2);
>         pool.setTestWhileIdle(true);
>         pool.setLifo(lifo);
>         PoolUtils.prefill(pool, 5);
>         pool.evict();
>         factory.setEvenValid(false);
>         factory.setOddValid(false);
>         factory.setThrowExceptionOnActivate(true);
>         pool.evict();
>         PoolUtils.prefill(pool, 5);
>         factory.setThrowExceptionOnActivate(false);
>         factory.setThrowExceptionOnPassivate(true);
>         pool.evict();
>         factory.setThrowExceptionOnPassivate(false);
>         factory.setEvenValid(true);
>         factory.setOddValid(true);
>         Thread.sleep(125);
>         pool.evict();
>         assertEquals(2, pool.getNumIdle());
>     }
> 
>     /**
>      * Test to make sure evictor visits least recently used objects first,
>      * regardless of FIFO/LIFO.
>      *
>      * JIRA: POOL-86
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictionOrder() throws Exception {
>         checkEvictionOrder(false);
>         tearDown();
>         setUp();
>         checkEvictionOrder(true);
>     }
> 
>     private void checkEvictionOrder(boolean lifo) throws Exception {
>         checkEvictionOrderPart1(lifo);
>         tearDown();
>         setUp();
>         checkEvictionOrderPart2(lifo);
>     }
> 
>     private void checkEvictionOrderPart1(boolean lifo) throws Exception {
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         // Order, oldest to youngest, is "0", "1", ...,"4"
>         pool.evict(); // Should evict "0" and "1"
>         Object obj = pool.borrowObject();
>         assertTrue("oldest not evicted", !obj.equals("0"));
>         assertTrue("second oldest not evicted", !obj.equals("1"));
>         // 2 should be next out for FIFO, 4 for LIFO
>         assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
>     }
> 
>     private void checkEvictionOrderPart2(boolean lifo) throws Exception {
>         // Two eviction runs in sequence
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         pool.evict(); // Should evict "0" and "1"
>         pool.evict(); // Should evict "2" and "3"
>         Object obj = pool.borrowObject();
>         assertEquals("Wrong instance remaining in pool", "4", obj);
>     }
> 
>     /**
>      * Verifies that the evictor visits objects in expected order
>      * and frequency.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testEvictorVisiting() throws Exception {
>         checkEvictorVisiting(true);
>         checkEvictorVisiting(false);
>     }
> 
>     private void checkEvictorVisiting(boolean lifo) throws Exception {
>         VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
>         GenericObjectPool<VisitTracker<Object>> trackerPool =
>                 new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(2);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // Visit oldest 2 - 0 and 1
>         VisitTracker<Object> obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         //  borrow, return, borrow, return
>         //  FIFO will move 0 and 1 to end
>         //  LIFO, 7 out, then in, then out, then in
>         trackerPool.evict();  // Should visit 2 and 3 in either case
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() >= 4) {
>                 assertEquals("Unexpected instance visited " + tracker.getId(),
>                         0, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         trackerFactory = new VisitTrackerFactory<Object>();
>         trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(3);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // 0, 1, 2
>         trackerPool.evict(); // 3, 4, 5
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         // borrow, return, borrow, return
>         //  FIFO 3,4,5,6,7,0,1,2
>         //  LIFO 7,6,5,4,3,2,1,0
>         // In either case, pointer should be at 6
>         trackerPool.evict();
>         // Should hit 6,7,0 - 0 for second time
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() != 0) {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         2, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         // Randomly generate a pools with random numTests
>         // and make sure evictor cycles through elements appropriately
>         int[] smallPrimes = {2, 3, 5, 7};
>         Random random = new Random();
>         random.setSeed(System.currentTimeMillis());
>         for (int i = 0; i < 4; i++) {
>             for (int j = 0; j < 5; j++) {
>                 trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>                 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
>                 trackerPool.setMinEvictableIdleTimeMillis(-1);
>                 trackerPool.setTestWhileIdle(true);
>                 trackerPool.setLifo(lifo);
>                 trackerPool.setTestOnReturn(false);
>                 trackerPool.setTestOnBorrow(false);
>                 trackerPool.setMaxIdle(-1);
>                 int instanceCount = 10 + random.nextInt(20);
>                 trackerPool.setMaxTotal(instanceCount);
>                 for (int k = 0; k < instanceCount; k++) {
>                     trackerPool.addObject();
>                 }
> 
>                 // Execute a random number of evictor runs
>                 int runs = 10 + random.nextInt(50);
>                 for (int k = 0; k < runs; k++) {
>                     trackerPool.evict();
>                 }
> 
>                 // Number of times evictor should have cycled through the pool
>                 int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
>                         instanceCount;
> 
>                 // Look at elements and make sure they are visited cycleCount
>                 // or cycleCount + 1 times
>                 VisitTracker<Object> tracker = null;
>                 int visitCount = 0;
>                 for (int k = 0; k < instanceCount; k++) {
>                     tracker = trackerPool.borrowObject();
>                     assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
>                     visitCount = tracker.getValidateCount();
>                     assertTrue(visitCount >= cycleCount &&
>                             visitCount <= cycleCount + 1);
>                 }
>                 trackerPool.close();
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnPassivateDuringReturn() throws Exception {
>         String obj = pool.borrowObject();
>         factory.setThrowExceptionOnPassivate(true);
>         pool.returnObject(obj);
>         assertEquals(0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringBorrow() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnBorrow(true);
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail on next borrow attempt
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringReturn() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnReturn(true);
>         String obj1 = pool.borrowObject();
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnActivateDuringBorrow() throws Exception {
>         String obj1 = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         pool.returnObject(obj1);
>         pool.returnObject(obj2);
>         factory.setThrowExceptionOnActivate(true);
>         factory.setEvenValid(false);
>         // Activation will now throw every other time
>         // First attempt throws, but loop continues and second succeeds
>         String obj = pool.borrowObject();
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
>         factory.setValid(false);
>         // Validation will now fail on activation when borrowObject returns
>         // an idle instance, and then when attempting to create a new instance
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(0, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testNegativeMaxTotal() throws Exception {
>         pool.setMaxTotal(-1);
>         pool.setBlockWhenExhausted(false);
>         String obj = pool.borrowObject();
>         assertEquals(getNthObject(0),obj);
>         pool.returnObject(obj);
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdle() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(8);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdleZero() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(0);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals(0, pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotal() throws Exception {
>         pool.setMaxTotal(3);
>         pool.setBlockWhenExhausted(false);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>         pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testTimeoutNoLeak() throws Exception {
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(10);
>         pool.setBlockWhenExhausted(true);
>         String obj = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         pool.returnObject(obj2);
>         pool.returnObject(obj);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalZero() throws Exception {
>         pool.setMaxTotal(0);
>         pool.setBlockWhenExhausted(false);
> 
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalUnderLoad() {
>         // Config
>         int numThreads = 199; // And main thread makes a round 200.
>         int numIter = 20;
>         int delay = 25;
>         int maxTotal = 10;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             // Factor of 2 on iterations so main thread does work whilst other
>             // threads are running. Factor of 2 on delay so average delay for
>             // other threads == actual delay for main thread
>             threads[i] = new TestThread(pool, numIter * 2, delay * 2);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         // Give the threads a chance to start doing some work
>         try {
>             Thread.sleep(5000);
>         } catch(InterruptedException e) {
>             // ignored
>         }
> 
>         for (int i = 0; i < numIter; i++) {
>             String obj = null;
>             try {
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 obj = pool.borrowObject();
>                 // Under load, observed _numActive > _maxTotal
>                 if (pool.getNumActive() > pool.getMaxTotal()) {
>                     throw new IllegalStateException("Too many active objects");
>                 }
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             } catch (Exception e) {
>                 // Shouldn't happen
>                 e.printStackTrace();
>                 fail("Exception on borrow");
>             } finally {
>                 if (obj != null) {
>                     try {
>                         pool.returnObject(obj);
>                     } catch (Exception e) {
>                         // Ignore
>                     }
>                 }
>             }
>         }
> 
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testSettersAndGetters() throws Exception {
>         {
>             // The object receives an Exception during its creation to prevent
>             // memory leaks. See BaseGenericObjectPool constructor for more details.
>             assertTrue(false == "".equals(pool.getCreationStackTrace()));
>         }
>         {
>             assertEquals(0, pool.getBorrowedCount());
>         }
>         {
>             assertEquals(0, pool.getReturnedCount());
>         }
>         {
>             assertEquals(0, pool.getCreatedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByEvictorCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByBorrowValidationCount());
>         }
>         {
>             assertEquals(0, pool.getMeanActiveTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanIdleTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getNumIdle());
>         }
>         {
>             pool.setMaxTotal(123);
>             assertEquals(123,pool.getMaxTotal());
>         }
>         {
>             pool.setMaxIdle(12);
>             assertEquals(12,pool.getMaxIdle());
>         }
>         {
>             pool.setMaxWaitMillis(1234L);
>             assertEquals(1234L,pool.getMaxWaitMillis());
>         }
>         {
>             pool.setMinEvictableIdleTimeMillis(12345L);
>             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setNumTestsPerEvictionRun(11);
>             assertEquals(11,pool.getNumTestsPerEvictionRun());
>         }
>         {
>             pool.setTestOnBorrow(true);
>             assertTrue(pool.getTestOnBorrow());
>             pool.setTestOnBorrow(false);
>             assertTrue(!pool.getTestOnBorrow());
>         }
>         {
>             pool.setTestOnReturn(true);
>             assertTrue(pool.getTestOnReturn());
>             pool.setTestOnReturn(false);
>             assertTrue(!pool.getTestOnReturn());
>         }
>         {
>             pool.setTestWhileIdle(true);
>             assertTrue(pool.getTestWhileIdle());
>             pool.setTestWhileIdle(false);
>             assertTrue(!pool.getTestWhileIdle());
>         }
>         {
>             pool.setTimeBetweenEvictionRunsMillis(11235L);
>             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
>         }
>         {
>             pool.setSoftMinEvictableIdleTimeMillis(12135L);
>             assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setBlockWhenExhausted(true);
>             assertTrue(pool.getBlockWhenExhausted());
>             pool.setBlockWhenExhausted(false);
>             assertFalse(pool.getBlockWhenExhausted());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testDefaultConfiguration() throws Exception {
>         assertConfiguration(new GenericObjectPoolConfig(),pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testSetConfig() throws Exception {
>         GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
>         assertConfiguration(expected,pool);
>         expected.setMaxTotal(2);
>         expected.setMaxIdle(3);
>         expected.setMaxWaitMillis(5L);
>         expected.setMinEvictableIdleTimeMillis(7L);
>         expected.setNumTestsPerEvictionRun(9);
>         expected.setTestOnCreate(true);
>         expected.setTestOnBorrow(true);
>         expected.setTestOnReturn(true);
>         expected.setTestWhileIdle(true);
>         expected.setTimeBetweenEvictionRunsMillis(11L);
>         expected.setBlockWhenExhausted(false);
>         pool.setConfig(expected);
>         assertConfiguration(expected,pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testStartAndStopEvictor() throws Exception {
>         // set up pool without evictor
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(6);
>         pool.setMinEvictableIdleTimeMillis(100L);
> 
>         for(int j=0;j<2;j++) {
>             // populate the pool
>             {
>                 String[] active = new String[6];
>                 for(int i=0;i<6;i++) {
>                     active[i] = pool.borrowObject();
>                 }
>                 for(int i=0;i<6;i++) {
>                     pool.returnObject(active[i]);
>                 }
>             }
> 
>             // note that it stays populated
>             assertEquals("Should have 6 idle",6,pool.getNumIdle());
> 
>             // start the evictor
>             pool.setTimeBetweenEvictionRunsMillis(50L);
> 
>             // wait a second (well, .2 seconds)
>             try { Thread.sleep(200L); } catch(InterruptedException e) { }
> 
>             // assert that the evictor has cleared out the pool
>             assertEquals("Should have 0 idle",0,pool.getNumIdle());
> 
>             // stop the evictor
>             pool.startEvictor(0L);
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionWithNegativeNumTests() throws Exception {
>         // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(-2);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
> 
>         String[] active = new String[6];
>         for(int i=0;i<6;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<6;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testEviction() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(100);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
> 
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {
> 
>         private AtomicInteger callCount = new AtomicInteger(0);
> 
>         @Override
>         public boolean evict(EvictionConfig config, PooledObject<T> underTest,
>                 int idleCount) {
>             if (callCount.incrementAndGet() > 1500) {
>                 return true;
>             } else {
>                 return false;
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionPolicy() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(500);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         // ClassNotFoundException
>         try {
>             pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // InstantiationException
>         try {
>             pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // IllegalAccessException
>         try {
>             pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
>         assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         // Eviction policy ignores first 1500 attempts to evict and then always
>         // evicts. After 1s, there should have been two runs of 500 tests so no
>         // evictions
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 500 idle", 500, pool.getNumIdle());
>         // A further 1s wasn't enough so allow 2s for the evictor to clear out
>         // all of the idle objects.
>         try { Thread.sleep(2000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 0 idle", 0, pool.getNumIdle());
>     }
> 
> 
>     @Test(timeout=60000)
>     public void testEvictionSoftMinIdle() throws Exception {
>         class TimeTest extends BasePooledObjectFactory<TimeTest> {
>             private final long createTime;
>             public TimeTest() {
>                 createTime = System.currentTimeMillis();
>             }
>             @Override
>             public TimeTest create() throws Exception {
>                 return new TimeTest();
>             }
>             @Override
>             public PooledObject<TimeTest> wrap(TimeTest value) {
>                 return new DefaultPooledObject<TimeTest>(value);
>             }
>             public long getCreateTime() {
>                 return createTime;
>             }
>         }
> 
>         GenericObjectPool<TimeTest> timePool =
>             new GenericObjectPool<TimeTest>(new TimeTest());
> 
>         timePool.setMaxIdle(5);
>         timePool.setMaxTotal(5);
>         timePool.setNumTestsPerEvictionRun(5);
>         timePool.setMinEvictableIdleTimeMillis(3000L);
>         timePool.setSoftMinEvictableIdleTimeMillis(1000L);
>         timePool.setMinIdle(2);
> 
>         TimeTest[] active = new TimeTest[5];
>         Long[] creationTime = new Long[5] ;
>         for(int i=0;i<5;i++) {
>             active[i] = timePool.borrowObject();
>             creationTime[i] = Long.valueOf((active[i]).getCreateTime());
>         }
> 
>         for(int i=0;i<5;i++) {
>             timePool.returnObject(active[i]);
>         }
> 
>         // Soft evict all but minIdle(2)
>         Thread.sleep(1500L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());
> 
>         // Hard evict the rest.
>         Thread.sleep(2000L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
>         timePool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionInvalid() throws Exception {
> 
>         final GenericObjectPool<Object> invalidFactoryPool =
>                 new GenericObjectPool<Object>(new InvalidFactory());
> 
>         invalidFactoryPool.setMaxIdle(1);
>         invalidFactoryPool.setMaxTotal(1);
>         invalidFactoryPool.setTestOnBorrow(false);
>         invalidFactoryPool.setTestOnReturn(false);
>         invalidFactoryPool.setTestWhileIdle(true);
>         invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
>         invalidFactoryPool.setNumTestsPerEvictionRun(1);
> 
>         Object p = invalidFactoryPool.borrowObject();
>         invalidFactoryPool.returnObject(p);
> 
>         // Run eviction in a separate thread
>         Thread t = new EvictionThread<Object>(invalidFactoryPool);
>         t.start();
> 
>         // Sleep to make sure evictor has started
>         Thread.sleep(300);
> 
>         try {
>             invalidFactoryPool.borrowObject(1);
>         } catch (NoSuchElementException nsee) {
>             // Ignore
>         }
> 
>         // Make sure evictor has finished
>         Thread.sleep(1000);
> 
>         // Should have an empty pool
>         assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
>         assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
>         invalidFactoryPool.close();
>     }
> 
>     /**
>      * POOL-231 - verify that concurrent invalidates of the same object do not
>      * corrupt pool destroyCount.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testConcurrentInvalidate() throws Exception {
>         // Get allObjects and idleObjects loaded with some instances
>         final int nObjects = 1000;
>         pool.setMaxTotal(nObjects);
>         pool.setMaxIdle(nObjects);
>         final String[] obj = new String[nObjects];
>         for (int i = 0; i < nObjects; i++) {
>             obj[i] = pool.borrowObject();
>         }
>         for (int i = 0; i < nObjects; i++) {
>             if (i % 2 == 0) {
>                 pool.returnObject(obj[i]);
>             }
>         }
>         final int nThreads = 20;
>         final int nIterations = 60;
>         final InvalidateThread[] threads = new InvalidateThread[nThreads];
>         // Randomly generated list of distinct invalidation targets
>         final ArrayList<Integer> targets = new ArrayList<Integer>();
>         final Random random = new Random();
>         for (int j = 0; j < nIterations; j++) {
>             // Get a random invalidation target
>             Integer targ = Integer.valueOf(random.nextInt(nObjects));
>             while (targets.contains(targ)) {
>                 targ = Integer.valueOf(random.nextInt(nObjects));
>             }
>             targets.add(targ);
>             // Launch nThreads threads all trying to invalidate the target
>             for (int i = 0; i < nThreads; i++) {
>                 threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
>             }
>             for (int i = 0; i < nThreads; i++) {
>                 new Thread(threads[i]).start();
>             }
>             boolean done = false;
>             while (!done) {
>                 done = true;
>                 for (int i = 0; i < nThreads; i++) {
>                     done = done && threads[i].complete();
>                 }
>                 Thread.sleep(100);
>             }
>         }
>         Assert.assertEquals(nIterations, pool.getDestroyedCount());
>     }
> 
>     /**
>      * Attempts to invalidate an object, swallowing IllegalStateException.
>      */
>     static class InvalidateThread implements Runnable {
>         private final String obj;
>         private final ObjectPool<String> pool;
>         private boolean done = false;
>         public InvalidateThread(ObjectPool<String> pool, String obj) {
>             this.obj = obj;
>             this.pool = pool;
>         }
>         @Override
>         public void run() {
>             try {
>                 pool.invalidateObject(obj);
>             } catch (IllegalStateException ex) {
>                 // Ignore
>             } catch (Exception ex) {
>                 Assert.fail("Unexpected exception " + ex.toString());
>             } finally {
>                 done = true;
>             }
>         }
>         public boolean complete() {
>             return done;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdle() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[5];
>         active[0] = pool.borrowObject();
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=1 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdleMaxTotal() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[10];
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
> 
>         for(int i=0 ; i<10 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
> 
>         for(int i=0 ; i<10 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     /**
>      * Kicks off <numThreads> test threads, each of which will go through
>      * <iterations> borrow-return cycles with random delay times <= delay
>      * in between.
>      */
>     private void runTestThreads(int numThreads, int iterations, int delay) {
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool,iterations,delay);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testThreaded1() throws Exception {
>         pool.setMaxTotal(15);
>         pool.setMaxIdle(15);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(20, 100, 50);
>     }
> 
>     /**
>      * Verifies that maxTotal is not exceeded when factory destroyObject
>      * has high latency, testOnReturn is set and there is high incidence of
>      * validation failures.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMaxTotalInvariant() throws Exception {
>         int maxTotal = 15;
>         factory.setEvenValid(false);     // Every other validation fails
>         factory.setDestroyLatency(100);  // Destroy takes 100 ms
>         factory.setMaxTotal(maxTotal); // (makes - destroys) bound
>         factory.setValidationEnabled(true);
>         pool.setMaxTotal(maxTotal);
>         pool.setMaxIdle(-1);
>         pool.setTestOnReturn(true);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(5, 10, 50);
>     }
> 
>     @Test(timeout=60000)
>     public void testConcurrentBorrowAndEvict() throws Exception {
> 
>         pool.setMaxTotal(1);
>         pool.addObject();
> 
>         for( int i=0; i<5000; i++) {
>             ConcurrentBorrowAndEvictThread one =
>                     new ConcurrentBorrowAndEvictThread(true);
>             ConcurrentBorrowAndEvictThread two =
>                     new ConcurrentBorrowAndEvictThread(false);
> 
>             one.start();
>             two.start();
>             one.join();
>             two.join();
> 
>             pool.returnObject(one.obj);
> 
>             /* Uncomment this for a progress indication
>             if (i % 10 == 0) {
>                 System.out.println(i/10);
>             }
>             */
>         }
>     }
> 
>     /**
>      * POOL-189
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockClosePool() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         Object obj1 = pool.borrowObject();
> 
>         // Make sure an object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
> 
>         // close the pool (Bug POOL-189)
>         pool.close();
> 
>         // Give interrupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>     }
> 
>     private class ConcurrentBorrowAndEvictThread extends Thread {
>         private boolean borrow;
>         public String obj;
> 
>         public ConcurrentBorrowAndEvictThread(boolean borrow) {
>             this.borrow = borrow;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 if (borrow) {
>                     obj = pool.borrowObject();
>                 } else {
>                     pool.evict();
>                 }
>             } catch (Exception e) { /* Ignore */}
>         }
>     }
> 
>     static class TestThread implements Runnable {
>         private final java.util.Random _random = new java.util.Random();
> 
>         // Thread config items
>         private final ObjectPool<String> _pool;
>         private final int _iter;
>         private final int _delay;
>         private final boolean _randomDelay;
>         private final Object _expectedObject;
> 
>         private volatile boolean _complete = false;
>         private volatile boolean _failed = false;
>         private volatile Throwable _error;
> 
>         public TestThread(ObjectPool<String> pool) {
>             this(pool, 100, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter) {
>             this(pool, iter, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay) {
>             this(pool, iter, delay, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay) {
>             this(pool, iter, delay, randomDelay, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay, Object obj) {
>             _pool = pool;
>             _iter = iter;
>             _delay = delay;
>             _randomDelay = randomDelay;
>             _expectedObject = obj;
>         }
> 
>         public boolean complete() {
>             return _complete;
>         }
> 
>         public boolean failed() {
>             return _failed;
>         }
> 
>         @Override
>         public void run() {
>             for(int i=0;i<_iter;i++) {
>                 long delay =
>                     _randomDelay ? (long)_random.nextInt(_delay) : _delay;
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 String obj = null;
>                 try {
>                     obj = _pool.borrowObject();
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 if (_expectedObject != null && !_expectedObject.equals(obj)) {
>                     _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 try {
>                     _pool.returnObject(obj);
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>             }
>             _complete = true;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testFIFO() throws Exception {
>         String o = null;
>         pool.setLifo(false);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Oldest", "0", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Youngest", "2", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testLIFO() throws Exception {
>         String o = null;
>         pool.setLifo(true);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Youngest", "2", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Oldest", "0", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testAddObject() throws Exception {
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         pool.addObject();
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>         String obj = pool.borrowObject();
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         assertEquals("should be one active", 1, pool.getNumActive());
>         pool.returnObject(obj);
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>     }
> 
>     protected GenericObjectPool<String> pool = null;
> 
>     private SimpleFactory factory = null;
> 
>     private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
>         assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
>                 Boolean.valueOf(actual.getTestOnCreate()));
>         assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
>                 Boolean.valueOf(actual.getTestOnBorrow()));
>         assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
>                 Boolean.valueOf(actual.getTestOnReturn()));
>         assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
>                 Boolean.valueOf(actual.getTestWhileIdle()));
>         assertEquals("whenExhaustedAction",
>                 Boolean.valueOf(expected.getBlockWhenExhausted()),
>                 Boolean.valueOf(actual.getBlockWhenExhausted()));
>         assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
>         assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
>         assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
>         assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
>         assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
>         assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
>     }
> 
>     public static class SimpleFactory implements PooledObjectFactory<String> {
>         public SimpleFactory() {
>             this(true);
>         }
>         public SimpleFactory(boolean valid) {
>             this(valid,valid);
>         }
>         public SimpleFactory(boolean evalid, boolean ovalid) {
>             evenValid = evalid;
>             oddValid = ovalid;
>         }
>         public synchronized void setValid(boolean valid) {
>             setEvenValid(valid);
>             setOddValid(valid);
>         }
>         public synchronized void setEvenValid(boolean valid) {
>             evenValid = valid;
>         }
>         public synchronized void setOddValid(boolean valid) {
>             oddValid = valid;
>         }
>         public synchronized void setThrowExceptionOnPassivate(boolean bool) {
>             exceptionOnPassivate = bool;
>         }
>         public synchronized void setMaxTotal(int maxTotal) {
>             this.maxTotal = maxTotal;
>         }
>         public synchronized void setDestroyLatency(long destroyLatency) {
>             this.destroyLatency = destroyLatency;
>         }
>         public synchronized void setMakeLatency(long makeLatency) {
>             this.makeLatency = makeLatency;
>         }
>         public synchronized void setValidateLatency(long validateLatency) {
>             this.validateLatency = validateLatency;
>         }
>         @Override
>         public PooledObject<String> makeObject() {
>             final long waitLatency;
>             synchronized(this) {
>                 activeCount++;
>                 if (activeCount > maxTotal) {
>                     throw new IllegalStateException(
>                         "Too many active instances: " + activeCount);
>                 }
>                 waitLatency = makeLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             final int counter;
>             synchronized(this) {
>                 counter = makeCounter++;
>             }
>             return new DefaultPooledObject<String>(String.valueOf(counter));
>         }
>         @Override
>         public void destroyObject(PooledObject<String> obj) throws Exception {
>             final long waitLatency;
>             final boolean hurl;
>             synchronized(this) {
>                 waitLatency = destroyLatency;
>                 hurl = exceptionOnDestroy;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             synchronized(this) {
>                 activeCount--;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         @Override
>         public boolean validateObject(PooledObject<String> obj) {
>             final boolean validate;
>             final boolean evenTest;
>             final boolean oddTest;
>             final long waitLatency;
>             final int counter;
>             synchronized(this) {
>                 validate = enableValidation;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>                 waitLatency = validateLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             if (validate) {
>                 return counter%2 == 0 ? evenTest : oddTest;
>             }
>             else {
>                 return true;
>             }
>         }
>         @Override
>         public void activateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             final boolean evenTest;
>             final boolean oddTest;
>             final int counter;
>             synchronized(this) {
>                 hurl = exceptionOnActivate;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>             }
>             if (hurl) {
>                 if (!(counter%2 == 0 ? evenTest : oddTest)) {
>                     throw new Exception();
>                 }
>             }
>         }
>         @Override
>         public void passivateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             synchronized(this) {
>                 hurl = exceptionOnPassivate;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         int makeCounter = 0;
>         int validateCounter = 0;
>         int activeCount = 0;
>         boolean evenValid = true;
>         boolean oddValid = true;
>         boolean exceptionOnPassivate = false;
>         boolean exceptionOnActivate = false;
>         boolean exceptionOnDestroy = false;
>         boolean enableValidation = true;
>         long destroyLatency = 0;
>         long makeLatency = 0;
>         long validateLatency = 0;
>         int maxTotal = Integer.MAX_VALUE;
> 
>         public synchronized boolean isThrowExceptionOnActivate() {
>             return exceptionOnActivate;
>         }
> 
>         public synchronized void setThrowExceptionOnActivate(boolean b) {
>             exceptionOnActivate = b;
>         }
> 
>         public synchronized void setThrowExceptionOnDestroy(boolean b) {
>             exceptionOnDestroy = b;
>         }
> 
>         public synchronized boolean isValidationEnabled() {
>             return enableValidation;
>         }
> 
>         public synchronized void setValidationEnabled(boolean b) {
>             enableValidation = b;
>         }
> 
>         public synchronized int getMakeCounter() {
>             return makeCounter;
>         }
> 
>         private void doWait(long latency) {
>             try {
>                 Thread.sleep(latency);
>             } catch (InterruptedException ex) {
>                 // ignore
>             }
>         }
>     }
>     @Override
>     protected boolean isLifo() {
>         return true;
>     }
> 
>     @Override
>     protected boolean isFifo() {
>         return false;
>     }
> 
>     /*
>      * Note: This test relies on timing for correct execution. There *should* be
>      * enough margin for this to work correctly on most (all?) systems but be
>      * aware of this if you see a failure of this test.
>      */
>     @Test(timeout=60000)
>     public void testBorrowObjectFairness() {
> 
>         // Config
>         int numThreads = 30;
>         int maxTotal = 10;
> 
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
>             Thread t = new Thread(threads[i]);
>             t.start();
>             // Short delay to ensure threads start in correct order
>             try {
>                 Thread.sleep(50);
>             } catch (InterruptedException e) {
>                 fail(e.toString());
>             }
>         }
> 
>         // Wait for threads to finish
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     /**
>      * On first borrow, first object fails validation, second object is OK.
>      * Subsequent borrows are OK. This was POOL-152.
>      */
>     @Test(timeout=60000)
>     public void testBrokenFactoryShouldNotBlockPool() {
>         int maxTotal = 1;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTestOnBorrow(true);
> 
>         // First borrow object will need to create a new object which will fail
>         // validation.
>         String obj = null;
>         Exception ex = null;
>         factory.setValid(false);
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e) {
>             ex = e;
>         }
>         // Failure expected
>         assertNotNull(ex);
>         assertTrue(ex instanceof NoSuchElementException);
>         assertNull(obj);
> 
>         // Configure factory to create valid objects so subsequent borrows work
>         factory.setValid(true);
> 
>         // Subsequent borrows should be OK
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e1) {
>             fail();
>         }
>         assertNotNull(obj);
>         try {
>             pool.returnObject(obj);
>         } catch (Exception e) {
>             fail();
>         }
>     }
> 
>     /*
>      * Very simple test thread that just tries to borrow an object from
>      * the provided pool returns it after a wait
>      */
>     static class WaitingTestThread extends Thread {
>         private final GenericObjectPool<String> _pool;
>         private final long _pause;
>         private Throwable _thrown;
> 
>         private long preborrow; // just before borrow
>         private long postborrow; //  borrow returned
>         private long postreturn; // after object was returned
>         private long ended;
>         private String objectId;
> 
>         public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
>             _pool = pool;
>             _pause = pause;
>             _thrown = null;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 preborrow = System.currentTimeMillis();
>                 String obj = _pool.borrowObject();
>                 objectId = obj;
>                 postborrow = System.currentTimeMillis();
>                 Thread.sleep(_pause);
>                 _pool.returnObject(obj);
>                 postreturn = System.currentTimeMillis();
>             } catch (Exception e) {
>                 _thrown = e;
>             } finally{
>                 ended = System.currentTimeMillis();
>             }
>         }
>     }
> 
>     private static final boolean DISPLAY_THREAD_DETAILS=
>         Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
>     // To pass this to a Maven test, use:
>     // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
>     // @see http://jira.codehaus.org/browse/SUREFIRE-121
> 
>     /*
>      * Test multi-threaded pool access.
>      * Multiple threads, but maxTotal only allows half the threads to succeed.
>      *
>      * This test was prompted by Continuum build failures in the Commons DBCP test case:
>      * TestPerUserPoolDataSource.testMultipleThreads2()
>      * Let's see if the this fails on Continuum too!
>      */
>     @Test(timeout=60000)
>     public void testMaxWaitMultiThreaded() throws Exception {
>         final long maxWait = 500; // wait for connection
>         final long holdTime = 2 * maxWait; // how long to hold connection
>         final int threads = 10; // number of threads to grab the object initially
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(maxWait);
>         pool.setMaxTotal(threads);
>         // Create enough threads so half the threads will have to wait
>         WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
>         for(int i=0; i < wtt.length; i++){
>             wtt[i] = new WaitingTestThread(pool,holdTime);
>         }
>         long origin = System.currentTimeMillis()-1000;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].start();
>         }
>         int failed = 0;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].join();
>             if (wtt[i]._thrown != null){
>                 failed++;
>             }
>         }
>         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
>             System.out.println(
>                     "MaxWait: " + maxWait +
>                     " HoldTime: " + holdTime +
>                      " MaxTotal: " + threads +
>                     " Threads: " + wtt.length +
>                     " Failed: " + failed
>                     );
>             for(int i=0; i < wtt.length; i++){
>                 WaitingTestThread wt = wtt[i];
>                 System.out.println(
>                         "Preborrow: " + (wt.preborrow-origin) +
>                         " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
>                         " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
>                         " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
>                         " Ended: " + (wt.ended-origin) +
>                         " ObjId: " + wt.objectId
>                         );
>             }
>         }
>         assertEquals("Expected half the threads to fail",wtt.length/2,failed);
>     }
> 
>     /**
>      * Test the following scenario:
>      *   Thread 1 borrows an instance
>      *   Thread 2 starts to borrow another instance before thread 1 returns its instance
>      *   Thread 1 returns its instance while thread 2 is validating its newly created instance
>      * The test verifies that the instance created by Thread 2 is not leaked.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMakeConcurrentWithReturn() throws Exception {
>         pool.setTestOnBorrow(true);
>         factory.setValid(true);
>         // Borrow and return an instance, with a short wait
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
>         thread1.start();
>         Thread.sleep(50); // wait for validation to succeed
>         // Slow down validation and borrow an instance
>         factory.setValidateLatency(400);
>         String instance = pool.borrowObject();
>         // Now make sure that we have not leaked an instance
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
>         pool.returnObject(instance);
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle());
>     }
> 
>     /**
>      * Ensure the pool is registered.
>      */
>     @Test(timeout=60000)
>     public void testJmxRegistration() {
>         ObjectName oname = pool.getJmxName();
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(oname, null);
>         Assert.assertEquals(1, result.size());
>         pool.jmxUnregister();
> 
>         GenericObjectPoolConfig config = new GenericObjectPoolConfig();
>         config.setJmxEnabled(false);
>         GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
>         assertNull(poolWithoutJmx.getJmxName());
>         config.setJmxEnabled(true);
>         poolWithoutJmx.jmxUnregister();
> 
>         config.setJmxNameBase(null);
>         GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
>         assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a checked out object is
>      * invalidated.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testInvalidateFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(500);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance
>         String obj = pool.borrowObject();
>         // Launch another thread - will block, but fail in 500 ms
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
>         thread2.start();
>         // Invalidate the object borrowed by this thread - should allow thread2 to create
>         Thread.sleep(20);
>         pool.invalidateObject(obj);
>         Thread.sleep(600); // Wait for thread2 to timeout
>         if (thread2._thrown != null) {
>             fail(thread2._thrown.toString());
>         }
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a returning object fails
>      * validation.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testValidationFailureOnReturnFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         factory.setValid(false); // Validate will always fail
>         factory.setValidationEnabled(true);
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(1500);
>         pool.setTestOnReturn(true);
>         pool.setTestOnBorrow(false);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance and return it after 500 ms (validation will fail)
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
>         thread2.start();
>         Thread.sleep(50);
>         // Try to borrow an object
>         String obj = pool.borrowObject();
>         pool.returnObject(obj);
>     }
> 
>     @Test
>     public void testSwallowedExceptionListener() {
>         pool.setSwallowedExceptionListener(null); // must simply return
>         final List<Exception> swallowedExceptions = new ArrayList<Exception>();
>         /*
>          * A simple listener, that will throw a OOM on 3rd exception.
>          */
>         final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
>             @Override
>             public void onSwallowException(Exception e) {
>                 if (swallowedExceptions.size() == 2) {
>                     throw new OutOfMemoryError();
>                 } else {
>                     swallowedExceptions.add(e);
>                 }
>             }
>         };
>         pool.setSwallowedExceptionListener(listener);
> 
>         Exception e1 = new Exception();
>         Exception e2 = new ArrayIndexOutOfBoundsException();
> 
>         pool.swallowException(e1);
>         pool.swallowException(e2);
> 
>         try {
>             pool.swallowException(e1);
>             fail("Not supposed to get here");
>         } catch (OutOfMemoryError oom) {
>             // expected
>         }
> 
>         assertEquals(2, swallowedExceptions.size());
>     }
> 
>     // POOL-248
>     @Test(expected=IllegalStateException.class)
>     public void testMultipleReturnOfSameObject() throws Exception {
>         final GenericObjectPool<String> pool = new GenericObjectPool<String>(
>                 factory, new GenericObjectPoolConfig());
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         String obj = pool.borrowObject();
> 
>         Assert.assertEquals(1, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>     }
> 
>     private static final class DummyFactory
>             extends BasePooledObjectFactory<Object> {
>         @Override
>         public Object create() throws Exception {
>             return null;
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>     }
> 
> 
>     private static class InvalidFactory
>             extends BasePooledObjectFactory<Object> {
> 
>         @Override
>         public Object create() throws Exception {
>             return new Object();
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
> 
>         @Override
>         public boolean validateObject(PooledObject<Object> obj) {
>             try {
>                 Thread.sleep(1000);
>             } catch (InterruptedException e) {
>                 // Ignore
>             }
>             return false;
>         }
>     }
> 
>     private static class EvictionThread<T> extends Thread {
> 
>         private final GenericObjectPool<T> pool;
> 
>         public EvictionThread(GenericObjectPool<T> pool) {
>             this.pool = pool;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 pool.evict();
>             } catch (Exception e) {
>                 // Ignore
>             }
>         }
>     }
> }
> /*
>  * Licensed to the Apache Software Foundation (ASF) under one or more
>  * contributor license agreements.  See the NOTICE file distributed with
>  * this work for additional information regarding copyright ownership.
>  * The ASF licenses this file to You under the Apache License, Version 2.0
>  * (the "License"); you may not use this file except in compliance with
>  * the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing, software
>  * distributed under the License is distributed on an "AS IS" BASIS,
>  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  * See the License for the specific language governing permissions and
>  * limitations under the License.
>  */
> 
> package org.apache.commons.pool2.impl;
> 
> import static org.junit.Assert.assertEquals;
> import static org.junit.Assert.assertFalse;
> import static org.junit.Assert.assertNotNull;
> import static org.junit.Assert.assertNull;
> import static org.junit.Assert.assertTrue;
> import static org.junit.Assert.fail;
> 
> import java.lang.management.ManagementFactory;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.NoSuchElementException;
> import java.util.Random;
> import java.util.Set;
> import java.util.concurrent.atomic.AtomicInteger;
> 
> import javax.management.MBeanServer;
> import javax.management.ObjectName;
> 
> import org.apache.commons.pool2.BasePooledObjectFactory;
> import org.apache.commons.pool2.ObjectPool;
> import org.apache.commons.pool2.PoolUtils;
> import org.apache.commons.pool2.PooledObject;
> import org.apache.commons.pool2.PooledObjectFactory;
> import org.apache.commons.pool2.SwallowedExceptionListener;
> import org.apache.commons.pool2.TestBaseObjectPool;
> import org.apache.commons.pool2.VisitTracker;
> import org.apache.commons.pool2.VisitTrackerFactory;
> import org.junit.After;
> import org.junit.Assert;
> import org.junit.Before;
> import org.junit.Test;
> 
> /**
>  * @version $Revision: 1569016 $
>  */
> public class TestGenericObjectPool extends TestBaseObjectPool {
> 
>     @Override
>     protected ObjectPool<String> makeEmptyPool(int mincap) {
>        GenericObjectPool<String> mtPool =
>                new GenericObjectPool<String>(new SimpleFactory());
>        mtPool.setMaxTotal(mincap);
>        mtPool.setMaxIdle(mincap);
>        return mtPool;
>     }
> 
>     @Override
>     protected ObjectPool<Object> makeEmptyPool(
>             final PooledObjectFactory<Object> fac) {
>         return new GenericObjectPool<Object>(fac);
>     }
> 
>     @Override
>     protected Object getNthObject(int n) {
>         return String.valueOf(n);
>     }
> 
>     @Before
>     public void setUp() throws Exception {
>         factory = new SimpleFactory();
>         pool = new GenericObjectPool<String>(factory);
>     }
> 
>     @After
>     public void tearDown() throws Exception {
>         String poolName = pool.getJmxName().toString();
>         pool.clear();
>         pool.close();
>         pool = null;
>         factory = null;
> 
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(new ObjectName(
>                 "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
>         // There should be no registered pools at this point
>         int registeredPoolCount = result.size();
>         StringBuilder msg = new StringBuilder("Current pool is: ");
>         msg.append(poolName);
>         msg.append("  Still open pools are: ");
>         for (ObjectName name : result) {
>             // Clean these up ready for the next test
>             msg.append(name.toString());
>             msg.append(" created via\n");
>             msg.append(mbs.getAttribute(name, "CreationStackTrace"));
>             msg.append('\n');
>             mbs.unregisterMBean(name);
>         }
>         Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
>     }
> 
>     @Test(expected=IllegalArgumentException.class)
>     public void testConstructorNullFactory() {
>         // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
>         assertNotNull(new GenericObjectPool<String>(null));
>         // TODO this currently causes tearDown to report an error
>         // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
>     }
> 
>     @Test(timeout=60000)
>     public void testConstructors() throws Exception {
> 
>         // Make constructor arguments all different from defaults
>         int minIdle = 2;
>         long maxWait = 3;
>         int maxIdle = 4;
>         int maxTotal = 5;
>         long minEvictableIdleTimeMillis = 6;
>         int numTestsPerEvictionRun = 7;
>         boolean testOnBorrow = true;
>         boolean testOnReturn = true;
>         boolean testWhileIdle = true;
>         long timeBetweenEvictionRunsMillis = 8;
>         boolean blockWhenExhausted = false;
>         boolean lifo = false;
>         PooledObjectFactory<Object> dummyFactory = new DummyFactory();
>         GenericObjectPool<Object> dummyPool =
>                 new GenericObjectPool<Object>(dummyFactory);
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
>                 dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
>                 Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
> 
>         GenericObjectPoolConfig config =
>                 new GenericObjectPoolConfig();
>         config.setLifo(lifo);
>         config.setMaxIdle(maxIdle);
>         config.setMinIdle(minIdle);
>         config.setMaxTotal(maxTotal);
>         config.setMaxWaitMillis(maxWait);
>         config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
>         config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
>         config.setTestOnBorrow(testOnBorrow);
>         config.setTestOnReturn(testOnReturn);
>         config.setTestWhileIdle(testWhileIdle);
>         config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
>         config.setBlockWhenExhausted(blockWhenExhausted);
>         dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
>         assertEquals(maxIdle, dummyPool.getMaxIdle());
>         assertEquals(maxWait, dummyPool.getMaxWaitMillis());
>         assertEquals(minIdle, dummyPool.getMinIdle());
>         assertEquals(maxTotal, dummyPool.getMaxTotal());
>         assertEquals(minEvictableIdleTimeMillis,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(testOnBorrow),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(testOnReturn),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(testWhileIdle),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(timeBetweenEvictionRunsMillis,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(blockWhenExhausted),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedFail() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(false);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumIdle());
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlock() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(10L);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockInterupt() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         String obj1 = pool.borrowObject();
> 
>         // Make sure on object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>         wtt.interrupt();
> 
>         // Give interupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
> 
>         // Return object to the pool
>         pool.returnObject(obj1);
> 
>         // Bug POOL-162 - check there is now an object in the pool
>         pool.setMaxWaitMillis(10L);
>         String obj2 = null;
>         try {
>              obj2 = pool.borrowObject();
>             assertNotNull(obj2);
>         } catch(NoSuchElementException e) {
>             // Not expected
>             fail("NoSuchElementException not expected");
>         }
>         pool.returnObject(obj2);
>         pool.close();
> 
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictWhileEmpty() throws Exception {
>         pool.evict();
>         pool.evict();
>         pool.close();
>     }
> 
>     /**
>      * Tests addObject contention between ensureMinIdle triggered by
>      * the Evictor with minIdle &gt; 0 and borrowObject.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictAddObjects() throws Exception {
>         factory.setMakeLatency(300);
>         factory.setMaxTotal(2);
>         pool.setMaxTotal(2);
>         pool.setMinIdle(1);
>         pool.borrowObject(); // numActive = 1, numIdle = 0
>         // Create a test thread that will run once and try a borrow after
>         // 150ms fixed delay
>         TestThread borrower = new TestThread(pool, 1, 150, false);
>         Thread borrowerThread = new Thread(borrower);
>         // Set evictor to run in 100 ms - will create idle instance
>         pool.setTimeBetweenEvictionRunsMillis(100);
>         borrowerThread.start();  // Off to the races
>         borrowerThread.join();
>         assertTrue(!borrower.failed());
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictLIFO() throws Exception {
>         checkEvict(true);
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictFIFO() throws Exception {
>         checkEvict(false);
>     }
> 
>     private void checkEvict(boolean lifo) throws Exception {
>         // yea this is hairy but it tests all the code paths in GOP.evict()
>         pool.setSoftMinEvictableIdleTimeMillis(10);
>         pool.setMinIdle(2);
>         pool.setTestWhileIdle(true);
>         pool.setLifo(lifo);
>         PoolUtils.prefill(pool, 5);
>         pool.evict();
>         factory.setEvenValid(false);
>         factory.setOddValid(false);
>         factory.setThrowExceptionOnActivate(true);
>         pool.evict();
>         PoolUtils.prefill(pool, 5);
>         factory.setThrowExceptionOnActivate(false);
>         factory.setThrowExceptionOnPassivate(true);
>         pool.evict();
>         factory.setThrowExceptionOnPassivate(false);
>         factory.setEvenValid(true);
>         factory.setOddValid(true);
>         Thread.sleep(125);
>         pool.evict();
>         assertEquals(2, pool.getNumIdle());
>     }
> 
>     /**
>      * Test to make sure evictor visits least recently used objects first,
>      * regardless of FIFO/LIFO.
>      *
>      * JIRA: POOL-86
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictionOrder() throws Exception {
>         checkEvictionOrder(false);
>         tearDown();
>         setUp();
>         checkEvictionOrder(true);
>     }
> 
>     private void checkEvictionOrder(boolean lifo) throws Exception {
>         checkEvictionOrderPart1(lifo);
>         tearDown();
>         setUp();
>         checkEvictionOrderPart2(lifo);
>     }
> 
>     private void checkEvictionOrderPart1(boolean lifo) throws Exception {
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         // Order, oldest to youngest, is "0", "1", ...,"4"
>         pool.evict(); // Should evict "0" and "1"
>         Object obj = pool.borrowObject();
>         assertTrue("oldest not evicted", !obj.equals("0"));
>         assertTrue("second oldest not evicted", !obj.equals("1"));
>         // 2 should be next out for FIFO, 4 for LIFO
>         assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
>     }
> 
>     private void checkEvictionOrderPart2(boolean lifo) throws Exception {
>         // Two eviction runs in sequence
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         pool.evict(); // Should evict "0" and "1"
>         pool.evict(); // Should evict "2" and "3"
>         Object obj = pool.borrowObject();
>         assertEquals("Wrong instance remaining in pool", "4", obj);
>     }
> 
>     /**
>      * Verifies that the evictor visits objects in expected order
>      * and frequency.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testEvictorVisiting() throws Exception {
>         checkEvictorVisiting(true);
>         checkEvictorVisiting(false);
>     }
> 
>     private void checkEvictorVisiting(boolean lifo) throws Exception {
>         VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
>         GenericObjectPool<VisitTracker<Object>> trackerPool =
>                 new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(2);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // Visit oldest 2 - 0 and 1
>         VisitTracker<Object> obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         //  borrow, return, borrow, return
>         //  FIFO will move 0 and 1 to end
>         //  LIFO, 7 out, then in, then out, then in
>         trackerPool.evict();  // Should visit 2 and 3 in either case
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() >= 4) {
>                 assertEquals("Unexpected instance visited " + tracker.getId(),
>                         0, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         trackerFactory = new VisitTrackerFactory<Object>();
>         trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(3);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // 0, 1, 2
>         trackerPool.evict(); // 3, 4, 5
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         // borrow, return, borrow, return
>         //  FIFO 3,4,5,6,7,0,1,2
>         //  LIFO 7,6,5,4,3,2,1,0
>         // In either case, pointer should be at 6
>         trackerPool.evict();
>         // Should hit 6,7,0 - 0 for second time
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() != 0) {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         2, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         // Randomly generate a pools with random numTests
>         // and make sure evictor cycles through elements appropriately
>         int[] smallPrimes = {2, 3, 5, 7};
>         Random random = new Random();
>         random.setSeed(System.currentTimeMillis());
>         for (int i = 0; i < 4; i++) {
>             for (int j = 0; j < 5; j++) {
>                 trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>                 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
>                 trackerPool.setMinEvictableIdleTimeMillis(-1);
>                 trackerPool.setTestWhileIdle(true);
>                 trackerPool.setLifo(lifo);
>                 trackerPool.setTestOnReturn(false);
>                 trackerPool.setTestOnBorrow(false);
>                 trackerPool.setMaxIdle(-1);
>                 int instanceCount = 10 + random.nextInt(20);
>                 trackerPool.setMaxTotal(instanceCount);
>                 for (int k = 0; k < instanceCount; k++) {
>                     trackerPool.addObject();
>                 }
> 
>                 // Execute a random number of evictor runs
>                 int runs = 10 + random.nextInt(50);
>                 for (int k = 0; k < runs; k++) {
>                     trackerPool.evict();
>                 }
> 
>                 // Number of times evictor should have cycled through the pool
>                 int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
>                         instanceCount;
> 
>                 // Look at elements and make sure they are visited cycleCount
>                 // or cycleCount + 1 times
>                 VisitTracker<Object> tracker = null;
>                 int visitCount = 0;
>                 for (int k = 0; k < instanceCount; k++) {
>                     tracker = trackerPool.borrowObject();
>                     assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
>                     visitCount = tracker.getValidateCount();
>                     assertTrue(visitCount >= cycleCount &&
>                             visitCount <= cycleCount + 1);
>                 }
>                 trackerPool.close();
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnPassivateDuringReturn() throws Exception {
>         String obj = pool.borrowObject();
>         factory.setThrowExceptionOnPassivate(true);
>         pool.returnObject(obj);
>         assertEquals(0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringBorrow() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnBorrow(true);
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail on next borrow attempt
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringReturn() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnReturn(true);
>         String obj1 = pool.borrowObject();
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnActivateDuringBorrow() throws Exception {
>         String obj1 = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         pool.returnObject(obj1);
>         pool.returnObject(obj2);
>         factory.setThrowExceptionOnActivate(true);
>         factory.setEvenValid(false);
>         // Activation will now throw every other time
>         // First attempt throws, but loop continues and second succeeds
>         String obj = pool.borrowObject();
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
>         factory.setValid(false);
>         // Validation will now fail on activation when borrowObject returns
>         // an idle instance, and then when attempting to create a new instance
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(0, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testNegativeMaxTotal() throws Exception {
>         pool.setMaxTotal(-1);
>         pool.setBlockWhenExhausted(false);
>         String obj = pool.borrowObject();
>         assertEquals(getNthObject(0),obj);
>         pool.returnObject(obj);
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdle() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(8);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdleZero() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(0);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals(0, pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotal() throws Exception {
>         pool.setMaxTotal(3);
>         pool.setBlockWhenExhausted(false);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>         pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testTimeoutNoLeak() throws Exception {
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(10);
>         pool.setBlockWhenExhausted(true);
>         String obj = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         pool.returnObject(obj2);
>         pool.returnObject(obj);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalZero() throws Exception {
>         pool.setMaxTotal(0);
>         pool.setBlockWhenExhausted(false);
> 
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalUnderLoad() {
>         // Config
>         int numThreads = 199; // And main thread makes a round 200.
>         int numIter = 20;
>         int delay = 25;
>         int maxTotal = 10;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             // Factor of 2 on iterations so main thread does work whilst other
>             // threads are running. Factor of 2 on delay so average delay for
>             // other threads == actual delay for main thread
>             threads[i] = new TestThread(pool, numIter * 2, delay * 2);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         // Give the threads a chance to start doing some work
>         try {
>             Thread.sleep(5000);
>         } catch(InterruptedException e) {
>             // ignored
>         }
> 
>         for (int i = 0; i < numIter; i++) {
>             String obj = null;
>             try {
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 obj = pool.borrowObject();
>                 // Under load, observed _numActive > _maxTotal
>                 if (pool.getNumActive() > pool.getMaxTotal()) {
>                     throw new IllegalStateException("Too many active objects");
>                 }
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             } catch (Exception e) {
>                 // Shouldn't happen
>                 e.printStackTrace();
>                 fail("Exception on borrow");
>             } finally {
>                 if (obj != null) {
>                     try {
>                         pool.returnObject(obj);
>                     } catch (Exception e) {
>                         // Ignore
>                     }
>                 }
>             }
>         }
> 
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testSettersAndGetters() throws Exception {
>         {
>             // The object receives an Exception during its creation to prevent
>             // memory leaks. See BaseGenericObjectPool constructor for more details.
>             assertTrue(false == "".equals(pool.getCreationStackTrace()));
>         }
>         {
>             assertEquals(0, pool.getBorrowedCount());
>         }
>         {
>             assertEquals(0, pool.getReturnedCount());
>         }
>         {
>             assertEquals(0, pool.getCreatedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByEvictorCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByBorrowValidationCount());
>         }
>         {
>             assertEquals(0, pool.getMeanActiveTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanIdleTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getNumIdle());
>         }
>         {
>             pool.setMaxTotal(123);
>             assertEquals(123,pool.getMaxTotal());
>         }
>         {
>             pool.setMaxIdle(12);
>             assertEquals(12,pool.getMaxIdle());
>         }
>         {
>             pool.setMaxWaitMillis(1234L);
>             assertEquals(1234L,pool.getMaxWaitMillis());
>         }
>         {
>             pool.setMinEvictableIdleTimeMillis(12345L);
>             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setNumTestsPerEvictionRun(11);
>             assertEquals(11,pool.getNumTestsPerEvictionRun());
>         }
>         {
>             pool.setTestOnBorrow(true);
>             assertTrue(pool.getTestOnBorrow());
>             pool.setTestOnBorrow(false);
>             assertTrue(!pool.getTestOnBorrow());
>         }
>         {
>             pool.setTestOnReturn(true);
>             assertTrue(pool.getTestOnReturn());
>             pool.setTestOnReturn(false);
>             assertTrue(!pool.getTestOnReturn());
>         }
>         {
>             pool.setTestWhileIdle(true);
>             assertTrue(pool.getTestWhileIdle());
>             pool.setTestWhileIdle(false);
>             assertTrue(!pool.getTestWhileIdle());
>         }
>         {
>             pool.setTimeBetweenEvictionRunsMillis(11235L);
>             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
>         }
>         {
>             pool.setSoftMinEvictableIdleTimeMillis(12135L);
>             assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setBlockWhenExhausted(true);
>             assertTrue(pool.getBlockWhenExhausted());
>             pool.setBlockWhenExhausted(false);
>             assertFalse(pool.getBlockWhenExhausted());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testDefaultConfiguration() throws Exception {
>         assertConfiguration(new GenericObjectPoolConfig(),pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testSetConfig() throws Exception {
>         GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
>         assertConfiguration(expected,pool);
>         expected.setMaxTotal(2);
>         expected.setMaxIdle(3);
>         expected.setMaxWaitMillis(5L);
>         expected.setMinEvictableIdleTimeMillis(7L);
>         expected.setNumTestsPerEvictionRun(9);
>         expected.setTestOnCreate(true);
>         expected.setTestOnBorrow(true);
>         expected.setTestOnReturn(true);
>         expected.setTestWhileIdle(true);
>         expected.setTimeBetweenEvictionRunsMillis(11L);
>         expected.setBlockWhenExhausted(false);
>         pool.setConfig(expected);
>         assertConfiguration(expected,pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testStartAndStopEvictor() throws Exception {
>         // set up pool without evictor
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(6);
>         pool.setMinEvictableIdleTimeMillis(100L);
> 
>         for(int j=0;j<2;j++) {
>             // populate the pool
>             {
>                 String[] active = new String[6];
>                 for(int i=0;i<6;i++) {
>                     active[i] = pool.borrowObject();
>                 }
>                 for(int i=0;i<6;i++) {
>                     pool.returnObject(active[i]);
>                 }
>             }
> 
>             // note that it stays populated
>             assertEquals("Should have 6 idle",6,pool.getNumIdle());
> 
>             // start the evictor
>             pool.setTimeBetweenEvictionRunsMillis(50L);
> 
>             // wait a second (well, .2 seconds)
>             try { Thread.sleep(200L); } catch(InterruptedException e) { }
> 
>             // assert that the evictor has cleared out the pool
>             assertEquals("Should have 0 idle",0,pool.getNumIdle());
> 
>             // stop the evictor
>             pool.startEvictor(0L);
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionWithNegativeNumTests() throws Exception {
>         // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(-2);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
> 
>         String[] active = new String[6];
>         for(int i=0;i<6;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<6;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testEviction() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(100);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
> 
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {
> 
>         private AtomicInteger callCount = new AtomicInteger(0);
> 
>         @Override
>         public boolean evict(EvictionConfig config, PooledObject<T> underTest,
>                 int idleCount) {
>             if (callCount.incrementAndGet() > 1500) {
>                 return true;
>             } else {
>                 return false;
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionPolicy() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(500);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         // ClassNotFoundException
>         try {
>             pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // InstantiationException
>         try {
>             pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // IllegalAccessException
>         try {
>             pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
>         assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         // Eviction policy ignores first 1500 attempts to evict and then always
>         // evicts. After 1s, there should have been two runs of 500 tests so no
>         // evictions
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 500 idle", 500, pool.getNumIdle());
>         // A further 1s wasn't enough so allow 2s for the evictor to clear out
>         // all of the idle objects.
>         try { Thread.sleep(2000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 0 idle", 0, pool.getNumIdle());
>     }
> 
> 
>     @Test(timeout=60000)
>     public void testEvictionSoftMinIdle() throws Exception {
>         class TimeTest extends BasePooledObjectFactory<TimeTest> {
>             private final long createTime;
>             public TimeTest() {
>                 createTime = System.currentTimeMillis();
>             }
>             @Override
>             public TimeTest create() throws Exception {
>                 return new TimeTest();
>             }
>             @Override
>             public PooledObject<TimeTest> wrap(TimeTest value) {
>                 return new DefaultPooledObject<TimeTest>(value);
>             }
>             public long getCreateTime() {
>                 return createTime;
>             }
>         }
> 
>         GenericObjectPool<TimeTest> timePool =
>             new GenericObjectPool<TimeTest>(new TimeTest());
> 
>         timePool.setMaxIdle(5);
>         timePool.setMaxTotal(5);
>         timePool.setNumTestsPerEvictionRun(5);
>         timePool.setMinEvictableIdleTimeMillis(3000L);
>         timePool.setSoftMinEvictableIdleTimeMillis(1000L);
>         timePool.setMinIdle(2);
> 
>         TimeTest[] active = new TimeTest[5];
>         Long[] creationTime = new Long[5] ;
>         for(int i=0;i<5;i++) {
>             active[i] = timePool.borrowObject();
>             creationTime[i] = Long.valueOf((active[i]).getCreateTime());
>         }
> 
>         for(int i=0;i<5;i++) {
>             timePool.returnObject(active[i]);
>         }
> 
>         // Soft evict all but minIdle(2)
>         Thread.sleep(1500L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());
> 
>         // Hard evict the rest.
>         Thread.sleep(2000L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
>         timePool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionInvalid() throws Exception {
> 
>         final GenericObjectPool<Object> invalidFactoryPool =
>                 new GenericObjectPool<Object>(new InvalidFactory());
> 
>         invalidFactoryPool.setMaxIdle(1);
>         invalidFactoryPool.setMaxTotal(1);
>         invalidFactoryPool.setTestOnBorrow(false);
>         invalidFactoryPool.setTestOnReturn(false);
>         invalidFactoryPool.setTestWhileIdle(true);
>         invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
>         invalidFactoryPool.setNumTestsPerEvictionRun(1);
> 
>         Object p = invalidFactoryPool.borrowObject();
>         invalidFactoryPool.returnObject(p);
> 
>         // Run eviction in a separate thread
>         Thread t = new EvictionThread<Object>(invalidFactoryPool);
>         t.start();
> 
>         // Sleep to make sure evictor has started
>         Thread.sleep(300);
> 
>         try {
>             invalidFactoryPool.borrowObject(1);
>         } catch (NoSuchElementException nsee) {
>             // Ignore
>         }
> 
>         // Make sure evictor has finished
>         Thread.sleep(1000);
> 
>         // Should have an empty pool
>         assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
>         assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
>         invalidFactoryPool.close();
>     }
> 
>     /**
>      * POOL-231 - verify that concurrent invalidates of the same object do not
>      * corrupt pool destroyCount.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testConcurrentInvalidate() throws Exception {
>         // Get allObjects and idleObjects loaded with some instances
>         final int nObjects = 1000;
>         pool.setMaxTotal(nObjects);
>         pool.setMaxIdle(nObjects);
>         final String[] obj = new String[nObjects];
>         for (int i = 0; i < nObjects; i++) {
>             obj[i] = pool.borrowObject();
>         }
>         for (int i = 0; i < nObjects; i++) {
>             if (i % 2 == 0) {
>                 pool.returnObject(obj[i]);
>             }
>         }
>         final int nThreads = 20;
>         final int nIterations = 60;
>         final InvalidateThread[] threads = new InvalidateThread[nThreads];
>         // Randomly generated list of distinct invalidation targets
>         final ArrayList<Integer> targets = new ArrayList<Integer>();
>         final Random random = new Random();
>         for (int j = 0; j < nIterations; j++) {
>             // Get a random invalidation target
>             Integer targ = Integer.valueOf(random.nextInt(nObjects));
>             while (targets.contains(targ)) {
>                 targ = Integer.valueOf(random.nextInt(nObjects));
>             }
>             targets.add(targ);
>             // Launch nThreads threads all trying to invalidate the target
>             for (int i = 0; i < nThreads; i++) {
>                 threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
>             }
>             for (int i = 0; i < nThreads; i++) {
>                 new Thread(threads[i]).start();
>             }
>             boolean done = false;
>             while (!done) {
>                 done = true;
>                 for (int i = 0; i < nThreads; i++) {
>                     done = done && threads[i].complete();
>                 }
>                 Thread.sleep(100);
>             }
>         }
>         Assert.assertEquals(nIterations, pool.getDestroyedCount());
>     }
> 
>     /**
>      * Attempts to invalidate an object, swallowing IllegalStateException.
>      */
>     static class InvalidateThread implements Runnable {
>         private final String obj;
>         private final ObjectPool<String> pool;
>         private boolean done = false;
>         public InvalidateThread(ObjectPool<String> pool, String obj) {
>             this.obj = obj;
>             this.pool = pool;
>         }
>         @Override
>         public void run() {
>             try {
>                 pool.invalidateObject(obj);
>             } catch (IllegalStateException ex) {
>                 // Ignore
>             } catch (Exception ex) {
>                 Assert.fail("Unexpected exception " + ex.toString());
>             } finally {
>                 done = true;
>             }
>         }
>         public boolean complete() {
>             return done;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdle() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[5];
>         active[0] = pool.borrowObject();
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=1 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdleMaxTotal() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[10];
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
> 
>         for(int i=0 ; i<10 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
> 
>         for(int i=0 ; i<10 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     /**
>      * Kicks off <numThreads> test threads, each of which will go through
>      * <iterations> borrow-return cycles with random delay times <= delay
>      * in between.
>      */
>     private void runTestThreads(int numThreads, int iterations, int delay) {
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool,iterations,delay);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testThreaded1() throws Exception {
>         pool.setMaxTotal(15);
>         pool.setMaxIdle(15);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(20, 100, 50);
>     }
> 
>     /**
>      * Verifies that maxTotal is not exceeded when factory destroyObject
>      * has high latency, testOnReturn is set and there is high incidence of
>      * validation failures.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMaxTotalInvariant() throws Exception {
>         int maxTotal = 15;
>         factory.setEvenValid(false);     // Every other validation fails
>         factory.setDestroyLatency(100);  // Destroy takes 100 ms
>         factory.setMaxTotal(maxTotal); // (makes - destroys) bound
>         factory.setValidationEnabled(true);
>         pool.setMaxTotal(maxTotal);
>         pool.setMaxIdle(-1);
>         pool.setTestOnReturn(true);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(5, 10, 50);
>     }
> 
>     @Test(timeout=60000)
>     public void testConcurrentBorrowAndEvict() throws Exception {
> 
>         pool.setMaxTotal(1);
>         pool.addObject();
> 
>         for( int i=0; i<5000; i++) {
>             ConcurrentBorrowAndEvictThread one =
>                     new ConcurrentBorrowAndEvictThread(true);
>             ConcurrentBorrowAndEvictThread two =
>                     new ConcurrentBorrowAndEvictThread(false);
> 
>             one.start();
>             two.start();
>             one.join();
>             two.join();
> 
>             pool.returnObject(one.obj);
> 
>             /* Uncomment this for a progress indication
>             if (i % 10 == 0) {
>                 System.out.println(i/10);
>             }
>             */
>         }
>     }
> 
>     /**
>      * POOL-189
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockClosePool() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         Object obj1 = pool.borrowObject();
> 
>         // Make sure an object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
> 
>         // close the pool (Bug POOL-189)
>         pool.close();
> 
>         // Give interrupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>     }
> 
>     private class ConcurrentBorrowAndEvictThread extends Thread {
>         private boolean borrow;
>         public String obj;
> 
>         public ConcurrentBorrowAndEvictThread(boolean borrow) {
>             this.borrow = borrow;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 if (borrow) {
>                     obj = pool.borrowObject();
>                 } else {
>                     pool.evict();
>                 }
>             } catch (Exception e) { /* Ignore */}
>         }
>     }
> 
>     static class TestThread implements Runnable {
>         private final java.util.Random _random = new java.util.Random();
> 
>         // Thread config items
>         private final ObjectPool<String> _pool;
>         private final int _iter;
>         private final int _delay;
>         private final boolean _randomDelay;
>         private final Object _expectedObject;
> 
>         private volatile boolean _complete = false;
>         private volatile boolean _failed = false;
>         private volatile Throwable _error;
> 
>         public TestThread(ObjectPool<String> pool) {
>             this(pool, 100, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter) {
>             this(pool, iter, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay) {
>             this(pool, iter, delay, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay) {
>             this(pool, iter, delay, randomDelay, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay, Object obj) {
>             _pool = pool;
>             _iter = iter;
>             _delay = delay;
>             _randomDelay = randomDelay;
>             _expectedObject = obj;
>         }
> 
>         public boolean complete() {
>             return _complete;
>         }
> 
>         public boolean failed() {
>             return _failed;
>         }
> 
>         @Override
>         public void run() {
>             for(int i=0;i<_iter;i++) {
>                 long delay =
>                     _randomDelay ? (long)_random.nextInt(_delay) : _delay;
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 String obj = null;
>                 try {
>                     obj = _pool.borrowObject();
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 if (_expectedObject != null && !_expectedObject.equals(obj)) {
>                     _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 try {
>                     _pool.returnObject(obj);
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>             }
>             _complete = true;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testFIFO() throws Exception {
>         String o = null;
>         pool.setLifo(false);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Oldest", "0", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Youngest", "2", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testLIFO() throws Exception {
>         String o = null;
>         pool.setLifo(true);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Youngest", "2", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Oldest", "0", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testAddObject() throws Exception {
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         pool.addObject();
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>         String obj = pool.borrowObject();
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         assertEquals("should be one active", 1, pool.getNumActive());
>         pool.returnObject(obj);
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>     }
> 
>     protected GenericObjectPool<String> pool = null;
> 
>     private SimpleFactory factory = null;
> 
>     private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
>         assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
>                 Boolean.valueOf(actual.getTestOnCreate()));
>         assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
>                 Boolean.valueOf(actual.getTestOnBorrow()));
>         assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
>                 Boolean.valueOf(actual.getTestOnReturn()));
>         assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
>                 Boolean.valueOf(actual.getTestWhileIdle()));
>         assertEquals("whenExhaustedAction",
>                 Boolean.valueOf(expected.getBlockWhenExhausted()),
>                 Boolean.valueOf(actual.getBlockWhenExhausted()));
>         assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
>         assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
>         assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
>         assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
>         assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
>         assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
>     }
> 
>     public static class SimpleFactory implements PooledObjectFactory<String> {
>         public SimpleFactory() {
>             this(true);
>         }
>         public SimpleFactory(boolean valid) {
>             this(valid,valid);
>         }
>         public SimpleFactory(boolean evalid, boolean ovalid) {
>             evenValid = evalid;
>             oddValid = ovalid;
>         }
>         public synchronized void setValid(boolean valid) {
>             setEvenValid(valid);
>             setOddValid(valid);
>         }
>         public synchronized void setEvenValid(boolean valid) {
>             evenValid = valid;
>         }
>         public synchronized void setOddValid(boolean valid) {
>             oddValid = valid;
>         }
>         public synchronized void setThrowExceptionOnPassivate(boolean bool) {
>             exceptionOnPassivate = bool;
>         }
>         public synchronized void setMaxTotal(int maxTotal) {
>             this.maxTotal = maxTotal;
>         }
>         public synchronized void setDestroyLatency(long destroyLatency) {
>             this.destroyLatency = destroyLatency;
>         }
>         public synchronized void setMakeLatency(long makeLatency) {
>             this.makeLatency = makeLatency;
>         }
>         public synchronized void setValidateLatency(long validateLatency) {
>             this.validateLatency = validateLatency;
>         }
>         @Override
>         public PooledObject<String> makeObject() {
>             final long waitLatency;
>             synchronized(this) {
>                 activeCount++;
>                 if (activeCount > maxTotal) {
>                     throw new IllegalStateException(
>                         "Too many active instances: " + activeCount);
>                 }
>                 waitLatency = makeLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             final int counter;
>             synchronized(this) {
>                 counter = makeCounter++;
>             }
>             return new DefaultPooledObject<String>(String.valueOf(counter));
>         }
>         @Override
>         public void destroyObject(PooledObject<String> obj) throws Exception {
>             final long waitLatency;
>             final boolean hurl;
>             synchronized(this) {
>                 waitLatency = destroyLatency;
>                 hurl = exceptionOnDestroy;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             synchronized(this) {
>                 activeCount--;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         @Override
>         public boolean validateObject(PooledObject<String> obj) {
>             final boolean validate;
>             final boolean evenTest;
>             final boolean oddTest;
>             final long waitLatency;
>             final int counter;
>             synchronized(this) {
>                 validate = enableValidation;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>                 waitLatency = validateLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             if (validate) {
>                 return counter%2 == 0 ? evenTest : oddTest;
>             }
>             else {
>                 return true;
>             }
>         }
>         @Override
>         public void activateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             final boolean evenTest;
>             final boolean oddTest;
>             final int counter;
>             synchronized(this) {
>                 hurl = exceptionOnActivate;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>             }
>             if (hurl) {
>                 if (!(counter%2 == 0 ? evenTest : oddTest)) {
>                     throw new Exception();
>                 }
>             }
>         }
>         @Override
>         public void passivateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             synchronized(this) {
>                 hurl = exceptionOnPassivate;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         int makeCounter = 0;
>         int validateCounter = 0;
>         int activeCount = 0;
>         boolean evenValid = true;
>         boolean oddValid = true;
>         boolean exceptionOnPassivate = false;
>         boolean exceptionOnActivate = false;
>         boolean exceptionOnDestroy = false;
>         boolean enableValidation = true;
>         long destroyLatency = 0;
>         long makeLatency = 0;
>         long validateLatency = 0;
>         int maxTotal = Integer.MAX_VALUE;
> 
>         public synchronized boolean isThrowExceptionOnActivate() {
>             return exceptionOnActivate;
>         }
> 
>         public synchronized void setThrowExceptionOnActivate(boolean b) {
>             exceptionOnActivate = b;
>         }
> 
>         public synchronized void setThrowExceptionOnDestroy(boolean b) {
>             exceptionOnDestroy = b;
>         }
> 
>         public synchronized boolean isValidationEnabled() {
>             return enableValidation;
>         }
> 
>         public synchronized void setValidationEnabled(boolean b) {
>             enableValidation = b;
>         }
> 
>         public synchronized int getMakeCounter() {
>             return makeCounter;
>         }
> 
>         private void doWait(long latency) {
>             try {
>                 Thread.sleep(latency);
>             } catch (InterruptedException ex) {
>                 // ignore
>             }
>         }
>     }
>     @Override
>     protected boolean isLifo() {
>         return true;
>     }
> 
>     @Override
>     protected boolean isFifo() {
>         return false;
>     }
> 
>     /*
>      * Note: This test relies on timing for correct execution. There *should* be
>      * enough margin for this to work correctly on most (all?) systems but be
>      * aware of this if you see a failure of this test.
>      */
>     @Test(timeout=60000)
>     public void testBorrowObjectFairness() {
> 
>         // Config
>         int numThreads = 30;
>         int maxTotal = 10;
> 
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
>             Thread t = new Thread(threads[i]);
>             t.start();
>             // Short delay to ensure threads start in correct order
>             try {
>                 Thread.sleep(50);
>             } catch (InterruptedException e) {
>                 fail(e.toString());
>             }
>         }
> 
>         // Wait for threads to finish
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     /**
>      * On first borrow, first object fails validation, second object is OK.
>      * Subsequent borrows are OK. This was POOL-152.
>      */
>     @Test(timeout=60000)
>     public void testBrokenFactoryShouldNotBlockPool() {
>         int maxTotal = 1;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTestOnBorrow(true);
> 
>         // First borrow object will need to create a new object which will fail
>         // validation.
>         String obj = null;
>         Exception ex = null;
>         factory.setValid(false);
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e) {
>             ex = e;
>         }
>         // Failure expected
>         assertNotNull(ex);
>         assertTrue(ex instanceof NoSuchElementException);
>         assertNull(obj);
> 
>         // Configure factory to create valid objects so subsequent borrows work
>         factory.setValid(true);
> 
>         // Subsequent borrows should be OK
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e1) {
>             fail();
>         }
>         assertNotNull(obj);
>         try {
>             pool.returnObject(obj);
>         } catch (Exception e) {
>             fail();
>         }
>     }
> 
>     /*
>      * Very simple test thread that just tries to borrow an object from
>      * the provided pool returns it after a wait
>      */
>     static class WaitingTestThread extends Thread {
>         private final GenericObjectPool<String> _pool;
>         private final long _pause;
>         private Throwable _thrown;
> 
>         private long preborrow; // just before borrow
>         private long postborrow; //  borrow returned
>         private long postreturn; // after object was returned
>         private long ended;
>         private String objectId;
> 
>         public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
>             _pool = pool;
>             _pause = pause;
>             _thrown = null;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 preborrow = System.currentTimeMillis();
>                 String obj = _pool.borrowObject();
>                 objectId = obj;
>                 postborrow = System.currentTimeMillis();
>                 Thread.sleep(_pause);
>                 _pool.returnObject(obj);
>                 postreturn = System.currentTimeMillis();
>             } catch (Exception e) {
>                 _thrown = e;
>             } finally{
>                 ended = System.currentTimeMillis();
>             }
>         }
>     }
> 
>     private static final boolean DISPLAY_THREAD_DETAILS=
>         Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
>     // To pass this to a Maven test, use:
>     // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
>     // @see http://jira.codehaus.org/browse/SUREFIRE-121
> 
>     /*
>      * Test multi-threaded pool access.
>      * Multiple threads, but maxTotal only allows half the threads to succeed.
>      *
>      * This test was prompted by Continuum build failures in the Commons DBCP test case:
>      * TestPerUserPoolDataSource.testMultipleThreads2()
>      * Let's see if the this fails on Continuum too!
>      */
>     @Test(timeout=60000)
>     public void testMaxWaitMultiThreaded() throws Exception {
>         final long maxWait = 500; // wait for connection
>         final long holdTime = 2 * maxWait; // how long to hold connection
>         final int threads = 10; // number of threads to grab the object initially
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(maxWait);
>         pool.setMaxTotal(threads);
>         // Create enough threads so half the threads will have to wait
>         WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
>         for(int i=0; i < wtt.length; i++){
>             wtt[i] = new WaitingTestThread(pool,holdTime);
>         }
>         long origin = System.currentTimeMillis()-1000;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].start();
>         }
>         int failed = 0;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].join();
>             if (wtt[i]._thrown != null){
>                 failed++;
>             }
>         }
>         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
>             System.out.println(
>                     "MaxWait: " + maxWait +
>                     " HoldTime: " + holdTime +
>                      " MaxTotal: " + threads +
>                     " Threads: " + wtt.length +
>                     " Failed: " + failed
>                     );
>             for(int i=0; i < wtt.length; i++){
>                 WaitingTestThread wt = wtt[i];
>                 System.out.println(
>                         "Preborrow: " + (wt.preborrow-origin) +
>                         " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
>                         " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
>                         " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
>                         " Ended: " + (wt.ended-origin) +
>                         " ObjId: " + wt.objectId
>                         );
>             }
>         }
>         assertEquals("Expected half the threads to fail",wtt.length/2,failed);
>     }
> 
>     /**
>      * Test the following scenario:
>      *   Thread 1 borrows an instance
>      *   Thread 2 starts to borrow another instance before thread 1 returns its instance
>      *   Thread 1 returns its instance while thread 2 is validating its newly created instance
>      * The test verifies that the instance created by Thread 2 is not leaked.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMakeConcurrentWithReturn() throws Exception {
>         pool.setTestOnBorrow(true);
>         factory.setValid(true);
>         // Borrow and return an instance, with a short wait
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
>         thread1.start();
>         Thread.sleep(50); // wait for validation to succeed
>         // Slow down validation and borrow an instance
>         factory.setValidateLatency(400);
>         String instance = pool.borrowObject();
>         // Now make sure that we have not leaked an instance
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
>         pool.returnObject(instance);
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle());
>     }
> 
>     /**
>      * Ensure the pool is registered.
>      */
>     @Test(timeout=60000)
>     public void testJmxRegistration() {
>         ObjectName oname = pool.getJmxName();
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(oname, null);
>         Assert.assertEquals(1, result.size());
>         pool.jmxUnregister();
> 
>         GenericObjectPoolConfig config = new GenericObjectPoolConfig();
>         config.setJmxEnabled(false);
>         GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
>         assertNull(poolWithoutJmx.getJmxName());
>         config.setJmxEnabled(true);
>         poolWithoutJmx.jmxUnregister();
> 
>         config.setJmxNameBase(null);
>         GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
>         assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a checked out object is
>      * invalidated.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testInvalidateFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(500);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance
>         String obj = pool.borrowObject();
>         // Launch another thread - will block, but fail in 500 ms
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
>         thread2.start();
>         // Invalidate the object borrowed by this thread - should allow thread2 to create
>         Thread.sleep(20);
>         pool.invalidateObject(obj);
>         Thread.sleep(600); // Wait for thread2 to timeout
>         if (thread2._thrown != null) {
>             fail(thread2._thrown.toString());
>         }
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a returning object fails
>      * validation.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testValidationFailureOnReturnFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         factory.setValid(false); // Validate will always fail
>         factory.setValidationEnabled(true);
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(1500);
>         pool.setTestOnReturn(true);
>         pool.setTestOnBorrow(false);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance and return it after 500 ms (validation will fail)
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
>         thread2.start();
>         Thread.sleep(50);
>         // Try to borrow an object
>         String obj = pool.borrowObject();
>         pool.returnObject(obj);
>     }
> 
>     @Test
>     public void testSwallowedExceptionListener() {
>         pool.setSwallowedExceptionListener(null); // must simply return
>         final List<Exception> swallowedExceptions = new ArrayList<Exception>();
>         /*
>          * A simple listener, that will throw a OOM on 3rd exception.
>          */
>         final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
>             @Override
>             public void onSwallowException(Exception e) {
>                 if (swallowedExceptions.size() == 2) {
>                     throw new OutOfMemoryError();
>                 } else {
>                     swallowedExceptions.add(e);
>                 }
>             }
>         };
>         pool.setSwallowedExceptionListener(listener);
> 
>         Exception e1 = new Exception();
>         Exception e2 = new ArrayIndexOutOfBoundsException();
> 
>         pool.swallowException(e1);
>         pool.swallowException(e2);
> 
>         try {
>             pool.swallowException(e1);
>             fail("Not supposed to get here");
>         } catch (OutOfMemoryError oom) {
>             // expected
>         }
> 
>         assertEquals(2, swallowedExceptions.size());
>     }
> 
>     // POOL-248
>     @Test(expected=IllegalStateException.class)
>     public void testMultipleReturnOfSameObject() throws Exception {
>         final GenericObjectPool<String> pool = new GenericObjectPool<String>(
>                 factory, new GenericObjectPoolConfig());
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         String obj = pool.borrowObject();
> 
>         Assert.assertEquals(1, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>     }
> 
>     private static final class DummyFactory
>             extends BasePooledObjectFactory<Object> {
>         @Override
>         public Object create() throws Exception {
>             return null;
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>     }
> 
> 
>     private static class InvalidFactory
>             extends BasePooledObjectFactory<Object> {
> 
>         @Override
>         public Object create() throws Exception {
>             return new Object();
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
> 
>         @Override
>         public boolean validateObject(PooledObject<Object> obj) {
>             try {
>                 Thread.sleep(1000);
>             } catch (InterruptedException e) {
>                 // Ignore
>             }
>             return false;
>         }
>     }
> 
>     private static class EvictionThread<T> extends Thread {
> 
>         private final GenericObjectPool<T> pool;
> 
>         public EvictionThread(GenericObjectPool<T> pool) {
>             this.pool = pool;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 pool.evict();
>             } catch (Exception e) {
>                 // Ignore
>             }
>         }
>     }
> }
> 
> Not sure of the meaning you are inferring with 'multiplexed'
> 
> Best of Luck in Brasil
> Martin 
> ______________________________________________ 
>  _____ _          _____             _          _____     ___ _                        _____               _     _   _         
> |_   _| |_ ___   |  _  |___ ___ ___| |_ ___   |   __|___|  _| |_ _ _ _ ___ ___ ___   |   __|___ _ _ ___ _| |___| |_|_|___ ___ 
>   | | |   | -_|  |     | . | .'|  _|   | -_|  |__   | . |  _|  _| | | | .'|  _| -_|  |   __| . | | |   | . | .'|  _| | . |   |
>   |_| |_|_|___|  |__|__|  _|__,|___|_|_|___|  |_____|___|_| |_| |_____|__,|_| |___|  |__|  |___|___|_|_|___|__,|_| |_|___|_|_|
>                        |_|                                                                                                    
> 
> 
> From: JLeskovar@telecomsys.com
> To: user@commons.apache.org
> Subject: Multiplexed connections in commons pool
> Date: Wed, 18 Jun 2014 23:07:44 +0000
> 
> 
> 
> 
> 
> 
> 
> 
> 
> Hi there,
>  
> I have an application that needs to perform connection pooling, with the proviso that it's okay - and actually preferable - for more than one client to checkout and use the same connection object from the pool. Ideally, I would also like
>  to limit the number of concurrent clients that are using a single connection object. I'm wondering what the best way to do this is. As a quick and dirty option, I suppose I could basically have my PooledObjectFactory return the same objects from makeObject(),
>  and manually keep track of objects from inside my implementation. Thoughts?
>  
> Cheers,
> James Leskovar
> 
> Software Engineer, Location Platforms
> TeleCommunication Systems, Inc.
> 
> 
> 
> [ Address : TCS, iC Enterprise 1, Innovation Campus, Squires Way, Nth Wollongong, NSW, 2500, Australia ]
> 
> [ Tel : +61 2 4221 2940 ] [ Fax : +61 2 4221 2901 ] 
> 
> [ Email : James.Leskovar@telecomsys.com ]
> 
>  
> 
> CONFIDENTIALITY NOTICE: The information contained in this message may be privileged and/or confidential. If you are not the intended recipient, or responsible for delivering this message to the intended recipient, any review, forwarding, dissemination, distribution or copying of this communication or any attachment(s) is strictly prohibited. If you have received this message in error, please notify the sender immediately, and delete it and all attachments from your computer and network.
>  		 	   		  
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
> For additional commands, e-mail: user-help@commons.apache.org
> 
 		 	   		  

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


RE: Multiplexed connections in commons pool

Posted by Martin Gainty <mg...@hotmail.com>.


> From: JLeskovar@telecomsys.com
> To: user@commons.apache.org
> Subject: RE: Multiplexed connections in commons pool
> Date: Thu, 19 Jun 2014 00:29:08 +0000
> 
> Hi Martin,
> 
> Thanks for the unit test - I'll check it out.
> 
> > Not sure of the meaning you are inferring with 'multiplexed'
> 
> I'm basically after having multiple calls to borrowObject<T>() return the same object - up to a limit - so that multiple clients can concurrently perform operations on the one connection object. So something like:
> 
> borrowObject() call #1 => returns object 1
> borrowObject() call #2 => returns object 1
> borrowObject() call #3 => returns object 1
MG>OK for read-only cursor
> borrowObject() call #4 => returns object 2
> borrowObject() call #5 => returns object 2
> borrowObject() call #6 => returns object 2
MG>Ok for read-only cursor

MG>Be careful of consequent requests with the same old cursor which doesnt refresh cursor buffer after COMMITS/ROLLBACKS
MG>with that same old cursor
MG>If you are doing any DML (update/insert/delete) operations I would close the connection & grab a new connection each time
> 
> etc..
> 
> Basically, I don't want to have too many open connections to a given remote service, and instead have just a few connections that multiple clients can use - i.e. have a 100 clients borrowObject()'ing over a limited number of connections.
> 
> Cheers,
> James
> 
> 
> -----Original Message-----
> From: Martin Gainty [mailto:mgainty@hotmail.com] 
> Sent: Thursday, 19 June 2014 10:14 AM
> To: Commons Users List
> Subject: RE: Multiplexed connections in commons pool
> 
> James-
> There is a nice test-case in 2.2 apache-commons that covers (Max-timeout-per-connection) and max-connections you are seeking:
> /*
>  * Licensed to the Apache Software Foundation (ASF) under one or more
>  * contributor license agreements.  See the NOTICE file distributed with
>  * this work for additional information regarding copyright ownership.
>  * The ASF licenses this file to You under the Apache License, Version 2.0
>  * (the "License"); you may not use this file except in compliance with
>  * the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing, software
>  * distributed under the License is distributed on an "AS IS" BASIS,
>  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  * See the License for the specific language governing permissions and
>  * limitations under the License.
>  */
> 
> package org.apache.commons.pool2.impl;
> 
> import static org.junit.Assert.assertEquals;
> import static org.junit.Assert.assertFalse;
> import static org.junit.Assert.assertNotNull;
> import static org.junit.Assert.assertNull;
> import static org.junit.Assert.assertTrue;
> import static org.junit.Assert.fail;
> 
> import java.lang.management.ManagementFactory;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.NoSuchElementException;
> import java.util.Random;
> import java.util.Set;
> import java.util.concurrent.atomic.AtomicInteger;
> 
> import javax.management.MBeanServer;
> import javax.management.ObjectName;
> 
> import org.apache.commons.pool2.BasePooledObjectFactory;
> import org.apache.commons.pool2.ObjectPool;
> import org.apache.commons.pool2.PoolUtils;
> import org.apache.commons.pool2.PooledObject;
> import org.apache.commons.pool2.PooledObjectFactory;
> import org.apache.commons.pool2.SwallowedExceptionListener;
> import org.apache.commons.pool2.TestBaseObjectPool;
> import org.apache.commons.pool2.VisitTracker;
> import org.apache.commons.pool2.VisitTrackerFactory;
> import org.junit.After;
> import org.junit.Assert;
> import org.junit.Before;
> import org.junit.Test;
> 
> /**
>  * @version $Revision: 1569016 $
>  */
> public class TestGenericObjectPool extends TestBaseObjectPool {
> 
>     @Override
>     protected ObjectPool<String> makeEmptyPool(int mincap) {
>        GenericObjectPool<String> mtPool =
>                new GenericObjectPool<String>(new SimpleFactory());
>        mtPool.setMaxTotal(mincap);
>        mtPool.setMaxIdle(mincap);
>        return mtPool;
>     }
> 
>     @Override
>     protected ObjectPool<Object> makeEmptyPool(
>             final PooledObjectFactory<Object> fac) {
>         return new GenericObjectPool<Object>(fac);
>     }
> 
>     @Override
>     protected Object getNthObject(int n) {
>         return String.valueOf(n);
>     }
> 
>     @Before
>     public void setUp() throws Exception {
>         factory = new SimpleFactory();
>         pool = new GenericObjectPool<String>(factory);
>     }
> 
>     @After
>     public void tearDown() throws Exception {
>         String poolName = pool.getJmxName().toString();
>         pool.clear();
>         pool.close();
>         pool = null;
>         factory = null;
> 
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(new ObjectName(
>                 "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
>         // There should be no registered pools at this point
>         int registeredPoolCount = result.size();
>         StringBuilder msg = new StringBuilder("Current pool is: ");
>         msg.append(poolName);
>         msg.append("  Still open pools are: ");
>         for (ObjectName name : result) {
>             // Clean these up ready for the next test
>             msg.append(name.toString());
>             msg.append(" created via\n");
>             msg.append(mbs.getAttribute(name, "CreationStackTrace"));
>             msg.append('\n');
>             mbs.unregisterMBean(name);
>         }
>         Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
>     }
> 
>     @Test(expected=IllegalArgumentException.class)
>     public void testConstructorNullFactory() {
>         // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
>         assertNotNull(new GenericObjectPool<String>(null));
>         // TODO this currently causes tearDown to report an error
>         // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
>     }
> 
>     @Test(timeout=60000)
>     public void testConstructors() throws Exception {
> 
>         // Make constructor arguments all different from defaults
>         int minIdle = 2;
>         long maxWait = 3;
>         int maxIdle = 4;
>         int maxTotal = 5;
>         long minEvictableIdleTimeMillis = 6;
>         int numTestsPerEvictionRun = 7;
>         boolean testOnBorrow = true;
>         boolean testOnReturn = true;
>         boolean testWhileIdle = true;
>         long timeBetweenEvictionRunsMillis = 8;
>         boolean blockWhenExhausted = false;
>         boolean lifo = false;
>         PooledObjectFactory<Object> dummyFactory = new DummyFactory();
>         GenericObjectPool<Object> dummyPool =
>                 new GenericObjectPool<Object>(dummyFactory);
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
>                 dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
>                 Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
> 
>         GenericObjectPoolConfig config =
>                 new GenericObjectPoolConfig();
>         config.setLifo(lifo);
>         config.setMaxIdle(maxIdle);
>         config.setMinIdle(minIdle);
>         config.setMaxTotal(maxTotal);
>         config.setMaxWaitMillis(maxWait);
>         config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
>         config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
>         config.setTestOnBorrow(testOnBorrow);
>         config.setTestOnReturn(testOnReturn);
>         config.setTestWhileIdle(testWhileIdle);
>         config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
>         config.setBlockWhenExhausted(blockWhenExhausted);
>         dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
>         assertEquals(maxIdle, dummyPool.getMaxIdle());
>         assertEquals(maxWait, dummyPool.getMaxWaitMillis());
>         assertEquals(minIdle, dummyPool.getMinIdle());
>         assertEquals(maxTotal, dummyPool.getMaxTotal());
>         assertEquals(minEvictableIdleTimeMillis,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(testOnBorrow),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(testOnReturn),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(testWhileIdle),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(timeBetweenEvictionRunsMillis,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(blockWhenExhausted),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedFail() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(false);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumIdle());
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlock() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(10L);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockInterupt() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         String obj1 = pool.borrowObject();
> 
>         // Make sure on object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>         wtt.interrupt();
> 
>         // Give interupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
> 
>         // Return object to the pool
>         pool.returnObject(obj1);
> 
>         // Bug POOL-162 - check there is now an object in the pool
>         pool.setMaxWaitMillis(10L);
>         String obj2 = null;
>         try {
>              obj2 = pool.borrowObject();
>             assertNotNull(obj2);
>         } catch(NoSuchElementException e) {
>             // Not expected
>             fail("NoSuchElementException not expected");
>         }
>         pool.returnObject(obj2);
>         pool.close();
> 
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictWhileEmpty() throws Exception {
>         pool.evict();
>         pool.evict();
>         pool.close();
>     }
> 
>     /**
>      * Tests addObject contention between ensureMinIdle triggered by
>      * the Evictor with minIdle &gt; 0 and borrowObject.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictAddObjects() throws Exception {
>         factory.setMakeLatency(300);
>         factory.setMaxTotal(2);
>         pool.setMaxTotal(2);
>         pool.setMinIdle(1);
>         pool.borrowObject(); // numActive = 1, numIdle = 0
>         // Create a test thread that will run once and try a borrow after
>         // 150ms fixed delay
>         TestThread borrower = new TestThread(pool, 1, 150, false);
>         Thread borrowerThread = new Thread(borrower);
>         // Set evictor to run in 100 ms - will create idle instance
>         pool.setTimeBetweenEvictionRunsMillis(100);
>         borrowerThread.start();  // Off to the races
>         borrowerThread.join();
>         assertTrue(!borrower.failed());
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictLIFO() throws Exception {
>         checkEvict(true);
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictFIFO() throws Exception {
>         checkEvict(false);
>     }
> 
>     private void checkEvict(boolean lifo) throws Exception {
>         // yea this is hairy but it tests all the code paths in GOP.evict()
>         pool.setSoftMinEvictableIdleTimeMillis(10);
>         pool.setMinIdle(2);
>         pool.setTestWhileIdle(true);
>         pool.setLifo(lifo);
>         PoolUtils.prefill(pool, 5);
>         pool.evict();
>         factory.setEvenValid(false);
>         factory.setOddValid(false);
>         factory.setThrowExceptionOnActivate(true);
>         pool.evict();
>         PoolUtils.prefill(pool, 5);
>         factory.setThrowExceptionOnActivate(false);
>         factory.setThrowExceptionOnPassivate(true);
>         pool.evict();
>         factory.setThrowExceptionOnPassivate(false);
>         factory.setEvenValid(true);
>         factory.setOddValid(true);
>         Thread.sleep(125);
>         pool.evict();
>         assertEquals(2, pool.getNumIdle());
>     }
> 
>     /**
>      * Test to make sure evictor visits least recently used objects first,
>      * regardless of FIFO/LIFO.
>      *
>      * JIRA: POOL-86
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictionOrder() throws Exception {
>         checkEvictionOrder(false);
>         tearDown();
>         setUp();
>         checkEvictionOrder(true);
>     }
> 
>     private void checkEvictionOrder(boolean lifo) throws Exception {
>         checkEvictionOrderPart1(lifo);
>         tearDown();
>         setUp();
>         checkEvictionOrderPart2(lifo);
>     }
> 
>     private void checkEvictionOrderPart1(boolean lifo) throws Exception {
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         // Order, oldest to youngest, is "0", "1", ...,"4"
>         pool.evict(); // Should evict "0" and "1"
>         Object obj = pool.borrowObject();
>         assertTrue("oldest not evicted", !obj.equals("0"));
>         assertTrue("second oldest not evicted", !obj.equals("1"));
>         // 2 should be next out for FIFO, 4 for LIFO
>         assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
>     }
> 
>     private void checkEvictionOrderPart2(boolean lifo) throws Exception {
>         // Two eviction runs in sequence
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         pool.evict(); // Should evict "0" and "1"
>         pool.evict(); // Should evict "2" and "3"
>         Object obj = pool.borrowObject();
>         assertEquals("Wrong instance remaining in pool", "4", obj);
>     }
> 
>     /**
>      * Verifies that the evictor visits objects in expected order
>      * and frequency.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testEvictorVisiting() throws Exception {
>         checkEvictorVisiting(true);
>         checkEvictorVisiting(false);
>     }
> 
>     private void checkEvictorVisiting(boolean lifo) throws Exception {
>         VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
>         GenericObjectPool<VisitTracker<Object>> trackerPool =
>                 new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(2);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // Visit oldest 2 - 0 and 1
>         VisitTracker<Object> obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         //  borrow, return, borrow, return
>         //  FIFO will move 0 and 1 to end
>         //  LIFO, 7 out, then in, then out, then in
>         trackerPool.evict();  // Should visit 2 and 3 in either case
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() >= 4) {
>                 assertEquals("Unexpected instance visited " + tracker.getId(),
>                         0, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         trackerFactory = new VisitTrackerFactory<Object>();
>         trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(3);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // 0, 1, 2
>         trackerPool.evict(); // 3, 4, 5
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         // borrow, return, borrow, return
>         //  FIFO 3,4,5,6,7,0,1,2
>         //  LIFO 7,6,5,4,3,2,1,0
>         // In either case, pointer should be at 6
>         trackerPool.evict();
>         // Should hit 6,7,0 - 0 for second time
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() != 0) {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         2, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         // Randomly generate a pools with random numTests
>         // and make sure evictor cycles through elements appropriately
>         int[] smallPrimes = {2, 3, 5, 7};
>         Random random = new Random();
>         random.setSeed(System.currentTimeMillis());
>         for (int i = 0; i < 4; i++) {
>             for (int j = 0; j < 5; j++) {
>                 trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>                 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
>                 trackerPool.setMinEvictableIdleTimeMillis(-1);
>                 trackerPool.setTestWhileIdle(true);
>                 trackerPool.setLifo(lifo);
>                 trackerPool.setTestOnReturn(false);
>                 trackerPool.setTestOnBorrow(false);
>                 trackerPool.setMaxIdle(-1);
>                 int instanceCount = 10 + random.nextInt(20);
>                 trackerPool.setMaxTotal(instanceCount);
>                 for (int k = 0; k < instanceCount; k++) {
>                     trackerPool.addObject();
>                 }
> 
>                 // Execute a random number of evictor runs
>                 int runs = 10 + random.nextInt(50);
>                 for (int k = 0; k < runs; k++) {
>                     trackerPool.evict();
>                 }
> 
>                 // Number of times evictor should have cycled through the pool
>                 int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
>                         instanceCount;
> 
>                 // Look at elements and make sure they are visited cycleCount
>                 // or cycleCount + 1 times
>                 VisitTracker<Object> tracker = null;
>                 int visitCount = 0;
>                 for (int k = 0; k < instanceCount; k++) {
>                     tracker = trackerPool.borrowObject();
>                     assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
>                     visitCount = tracker.getValidateCount();
>                     assertTrue(visitCount >= cycleCount &&
>                             visitCount <= cycleCount + 1);
>                 }
>                 trackerPool.close();
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnPassivateDuringReturn() throws Exception {
>         String obj = pool.borrowObject();
>         factory.setThrowExceptionOnPassivate(true);
>         pool.returnObject(obj);
>         assertEquals(0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringBorrow() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnBorrow(true);
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail on next borrow attempt
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringReturn() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnReturn(true);
>         String obj1 = pool.borrowObject();
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnActivateDuringBorrow() throws Exception {
>         String obj1 = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         pool.returnObject(obj1);
>         pool.returnObject(obj2);
>         factory.setThrowExceptionOnActivate(true);
>         factory.setEvenValid(false);
>         // Activation will now throw every other time
>         // First attempt throws, but loop continues and second succeeds
>         String obj = pool.borrowObject();
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
>         factory.setValid(false);
>         // Validation will now fail on activation when borrowObject returns
>         // an idle instance, and then when attempting to create a new instance
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(0, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testNegativeMaxTotal() throws Exception {
>         pool.setMaxTotal(-1);
>         pool.setBlockWhenExhausted(false);
>         String obj = pool.borrowObject();
>         assertEquals(getNthObject(0),obj);
>         pool.returnObject(obj);
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdle() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(8);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdleZero() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(0);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals(0, pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotal() throws Exception {
>         pool.setMaxTotal(3);
>         pool.setBlockWhenExhausted(false);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>         pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testTimeoutNoLeak() throws Exception {
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(10);
>         pool.setBlockWhenExhausted(true);
>         String obj = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         pool.returnObject(obj2);
>         pool.returnObject(obj);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalZero() throws Exception {
>         pool.setMaxTotal(0);
>         pool.setBlockWhenExhausted(false);
> 
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalUnderLoad() {
>         // Config
>         int numThreads = 199; // And main thread makes a round 200.
>         int numIter = 20;
>         int delay = 25;
>         int maxTotal = 10;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             // Factor of 2 on iterations so main thread does work whilst other
>             // threads are running. Factor of 2 on delay so average delay for
>             // other threads == actual delay for main thread
>             threads[i] = new TestThread(pool, numIter * 2, delay * 2);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         // Give the threads a chance to start doing some work
>         try {
>             Thread.sleep(5000);
>         } catch(InterruptedException e) {
>             // ignored
>         }
> 
>         for (int i = 0; i < numIter; i++) {
>             String obj = null;
>             try {
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 obj = pool.borrowObject();
>                 // Under load, observed _numActive > _maxTotal
>                 if (pool.getNumActive() > pool.getMaxTotal()) {
>                     throw new IllegalStateException("Too many active objects");
>                 }
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             } catch (Exception e) {
>                 // Shouldn't happen
>                 e.printStackTrace();
>                 fail("Exception on borrow");
>             } finally {
>                 if (obj != null) {
>                     try {
>                         pool.returnObject(obj);
>                     } catch (Exception e) {
>                         // Ignore
>                     }
>                 }
>             }
>         }
> 
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testSettersAndGetters() throws Exception {
>         {
>             // The object receives an Exception during its creation to prevent
>             // memory leaks. See BaseGenericObjectPool constructor for more details.
>             assertTrue(false == "".equals(pool.getCreationStackTrace()));
>         }
>         {
>             assertEquals(0, pool.getBorrowedCount());
>         }
>         {
>             assertEquals(0, pool.getReturnedCount());
>         }
>         {
>             assertEquals(0, pool.getCreatedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByEvictorCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByBorrowValidationCount());
>         }
>         {
>             assertEquals(0, pool.getMeanActiveTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanIdleTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getNumIdle());
>         }
>         {
>             pool.setMaxTotal(123);
>             assertEquals(123,pool.getMaxTotal());
>         }
>         {
>             pool.setMaxIdle(12);
>             assertEquals(12,pool.getMaxIdle());
>         }
>         {
>             pool.setMaxWaitMillis(1234L);
>             assertEquals(1234L,pool.getMaxWaitMillis());
>         }
>         {
>             pool.setMinEvictableIdleTimeMillis(12345L);
>             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setNumTestsPerEvictionRun(11);
>             assertEquals(11,pool.getNumTestsPerEvictionRun());
>         }
>         {
>             pool.setTestOnBorrow(true);
>             assertTrue(pool.getTestOnBorrow());
>             pool.setTestOnBorrow(false);
>             assertTrue(!pool.getTestOnBorrow());
>         }
>         {
>             pool.setTestOnReturn(true);
>             assertTrue(pool.getTestOnReturn());
>             pool.setTestOnReturn(false);
>             assertTrue(!pool.getTestOnReturn());
>         }
>         {
>             pool.setTestWhileIdle(true);
>             assertTrue(pool.getTestWhileIdle());
>             pool.setTestWhileIdle(false);
>             assertTrue(!pool.getTestWhileIdle());
>         }
>         {
>             pool.setTimeBetweenEvictionRunsMillis(11235L);
>             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
>         }
>         {
>             pool.setSoftMinEvictableIdleTimeMillis(12135L);
>             assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setBlockWhenExhausted(true);
>             assertTrue(pool.getBlockWhenExhausted());
>             pool.setBlockWhenExhausted(false);
>             assertFalse(pool.getBlockWhenExhausted());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testDefaultConfiguration() throws Exception {
>         assertConfiguration(new GenericObjectPoolConfig(),pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testSetConfig() throws Exception {
>         GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
>         assertConfiguration(expected,pool);
>         expected.setMaxTotal(2);
>         expected.setMaxIdle(3);
>         expected.setMaxWaitMillis(5L);
>         expected.setMinEvictableIdleTimeMillis(7L);
>         expected.setNumTestsPerEvictionRun(9);
>         expected.setTestOnCreate(true);
>         expected.setTestOnBorrow(true);
>         expected.setTestOnReturn(true);
>         expected.setTestWhileIdle(true);
>         expected.setTimeBetweenEvictionRunsMillis(11L);
>         expected.setBlockWhenExhausted(false);
>         pool.setConfig(expected);
>         assertConfiguration(expected,pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testStartAndStopEvictor() throws Exception {
>         // set up pool without evictor
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(6);
>         pool.setMinEvictableIdleTimeMillis(100L);
> 
>         for(int j=0;j<2;j++) {
>             // populate the pool
>             {
>                 String[] active = new String[6];
>                 for(int i=0;i<6;i++) {
>                     active[i] = pool.borrowObject();
>                 }
>                 for(int i=0;i<6;i++) {
>                     pool.returnObject(active[i]);
>                 }
>             }
> 
>             // note that it stays populated
>             assertEquals("Should have 6 idle",6,pool.getNumIdle());
> 
>             // start the evictor
>             pool.setTimeBetweenEvictionRunsMillis(50L);
> 
>             // wait a second (well, .2 seconds)
>             try { Thread.sleep(200L); } catch(InterruptedException e) { }
> 
>             // assert that the evictor has cleared out the pool
>             assertEquals("Should have 0 idle",0,pool.getNumIdle());
> 
>             // stop the evictor
>             pool.startEvictor(0L);
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionWithNegativeNumTests() throws Exception {
>         // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(-2);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
> 
>         String[] active = new String[6];
>         for(int i=0;i<6;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<6;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testEviction() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(100);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
> 
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {
> 
>         private AtomicInteger callCount = new AtomicInteger(0);
> 
>         @Override
>         public boolean evict(EvictionConfig config, PooledObject<T> underTest,
>                 int idleCount) {
>             if (callCount.incrementAndGet() > 1500) {
>                 return true;
>             } else {
>                 return false;
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionPolicy() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(500);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         // ClassNotFoundException
>         try {
>             pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // InstantiationException
>         try {
>             pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // IllegalAccessException
>         try {
>             pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
>         assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         // Eviction policy ignores first 1500 attempts to evict and then always
>         // evicts. After 1s, there should have been two runs of 500 tests so no
>         // evictions
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 500 idle", 500, pool.getNumIdle());
>         // A further 1s wasn't enough so allow 2s for the evictor to clear out
>         // all of the idle objects.
>         try { Thread.sleep(2000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 0 idle", 0, pool.getNumIdle());
>     }
> 
> 
>     @Test(timeout=60000)
>     public void testEvictionSoftMinIdle() throws Exception {
>         class TimeTest extends BasePooledObjectFactory<TimeTest> {
>             private final long createTime;
>             public TimeTest() {
>                 createTime = System.currentTimeMillis();
>             }
>             @Override
>             public TimeTest create() throws Exception {
>                 return new TimeTest();
>             }
>             @Override
>             public PooledObject<TimeTest> wrap(TimeTest value) {
>                 return new DefaultPooledObject<TimeTest>(value);
>             }
>             public long getCreateTime() {
>                 return createTime;
>             }
>         }
> 
>         GenericObjectPool<TimeTest> timePool =
>             new GenericObjectPool<TimeTest>(new TimeTest());
> 
>         timePool.setMaxIdle(5);
>         timePool.setMaxTotal(5);
>         timePool.setNumTestsPerEvictionRun(5);
>         timePool.setMinEvictableIdleTimeMillis(3000L);
>         timePool.setSoftMinEvictableIdleTimeMillis(1000L);
>         timePool.setMinIdle(2);
> 
>         TimeTest[] active = new TimeTest[5];
>         Long[] creationTime = new Long[5] ;
>         for(int i=0;i<5;i++) {
>             active[i] = timePool.borrowObject();
>             creationTime[i] = Long.valueOf((active[i]).getCreateTime());
>         }
> 
>         for(int i=0;i<5;i++) {
>             timePool.returnObject(active[i]);
>         }
> 
>         // Soft evict all but minIdle(2)
>         Thread.sleep(1500L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());
> 
>         // Hard evict the rest.
>         Thread.sleep(2000L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
>         timePool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionInvalid() throws Exception {
> 
>         final GenericObjectPool<Object> invalidFactoryPool =
>                 new GenericObjectPool<Object>(new InvalidFactory());
> 
>         invalidFactoryPool.setMaxIdle(1);
>         invalidFactoryPool.setMaxTotal(1);
>         invalidFactoryPool.setTestOnBorrow(false);
>         invalidFactoryPool.setTestOnReturn(false);
>         invalidFactoryPool.setTestWhileIdle(true);
>         invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
>         invalidFactoryPool.setNumTestsPerEvictionRun(1);
> 
>         Object p = invalidFactoryPool.borrowObject();
>         invalidFactoryPool.returnObject(p);
> 
>         // Run eviction in a separate thread
>         Thread t = new EvictionThread<Object>(invalidFactoryPool);
>         t.start();
> 
>         // Sleep to make sure evictor has started
>         Thread.sleep(300);
> 
>         try {
>             invalidFactoryPool.borrowObject(1);
>         } catch (NoSuchElementException nsee) {
>             // Ignore
>         }
> 
>         // Make sure evictor has finished
>         Thread.sleep(1000);
> 
>         // Should have an empty pool
>         assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
>         assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
>         invalidFactoryPool.close();
>     }
> 
>     /**
>      * POOL-231 - verify that concurrent invalidates of the same object do not
>      * corrupt pool destroyCount.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testConcurrentInvalidate() throws Exception {
>         // Get allObjects and idleObjects loaded with some instances
>         final int nObjects = 1000;
>         pool.setMaxTotal(nObjects);
>         pool.setMaxIdle(nObjects);
>         final String[] obj = new String[nObjects];
>         for (int i = 0; i < nObjects; i++) {
>             obj[i] = pool.borrowObject();
>         }
>         for (int i = 0; i < nObjects; i++) {
>             if (i % 2 == 0) {
>                 pool.returnObject(obj[i]);
>             }
>         }
>         final int nThreads = 20;
>         final int nIterations = 60;
>         final InvalidateThread[] threads = new InvalidateThread[nThreads];
>         // Randomly generated list of distinct invalidation targets
>         final ArrayList<Integer> targets = new ArrayList<Integer>();
>         final Random random = new Random();
>         for (int j = 0; j < nIterations; j++) {
>             // Get a random invalidation target
>             Integer targ = Integer.valueOf(random.nextInt(nObjects));
>             while (targets.contains(targ)) {
>                 targ = Integer.valueOf(random.nextInt(nObjects));
>             }
>             targets.add(targ);
>             // Launch nThreads threads all trying to invalidate the target
>             for (int i = 0; i < nThreads; i++) {
>                 threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
>             }
>             for (int i = 0; i < nThreads; i++) {
>                 new Thread(threads[i]).start();
>             }
>             boolean done = false;
>             while (!done) {
>                 done = true;
>                 for (int i = 0; i < nThreads; i++) {
>                     done = done && threads[i].complete();
>                 }
>                 Thread.sleep(100);
>             }
>         }
>         Assert.assertEquals(nIterations, pool.getDestroyedCount());
>     }
> 
>     /**
>      * Attempts to invalidate an object, swallowing IllegalStateException.
>      */
>     static class InvalidateThread implements Runnable {
>         private final String obj;
>         private final ObjectPool<String> pool;
>         private boolean done = false;
>         public InvalidateThread(ObjectPool<String> pool, String obj) {
>             this.obj = obj;
>             this.pool = pool;
>         }
>         @Override
>         public void run() {
>             try {
>                 pool.invalidateObject(obj);
>             } catch (IllegalStateException ex) {
>                 // Ignore
>             } catch (Exception ex) {
>                 Assert.fail("Unexpected exception " + ex.toString());
>             } finally {
>                 done = true;
>             }
>         }
>         public boolean complete() {
>             return done;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdle() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[5];
>         active[0] = pool.borrowObject();
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=1 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdleMaxTotal() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[10];
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
> 
>         for(int i=0 ; i<10 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
> 
>         for(int i=0 ; i<10 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     /**
>      * Kicks off <numThreads> test threads, each of which will go through
>      * <iterations> borrow-return cycles with random delay times <= delay
>      * in between.
>      */
>     private void runTestThreads(int numThreads, int iterations, int delay) {
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool,iterations,delay);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testThreaded1() throws Exception {
>         pool.setMaxTotal(15);
>         pool.setMaxIdle(15);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(20, 100, 50);
>     }
> 
>     /**
>      * Verifies that maxTotal is not exceeded when factory destroyObject
>      * has high latency, testOnReturn is set and there is high incidence of
>      * validation failures.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMaxTotalInvariant() throws Exception {
>         int maxTotal = 15;
>         factory.setEvenValid(false);     // Every other validation fails
>         factory.setDestroyLatency(100);  // Destroy takes 100 ms
>         factory.setMaxTotal(maxTotal); // (makes - destroys) bound
>         factory.setValidationEnabled(true);
>         pool.setMaxTotal(maxTotal);
>         pool.setMaxIdle(-1);
>         pool.setTestOnReturn(true);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(5, 10, 50);
>     }
> 
>     @Test(timeout=60000)
>     public void testConcurrentBorrowAndEvict() throws Exception {
> 
>         pool.setMaxTotal(1);
>         pool.addObject();
> 
>         for( int i=0; i<5000; i++) {
>             ConcurrentBorrowAndEvictThread one =
>                     new ConcurrentBorrowAndEvictThread(true);
>             ConcurrentBorrowAndEvictThread two =
>                     new ConcurrentBorrowAndEvictThread(false);
> 
>             one.start();
>             two.start();
>             one.join();
>             two.join();
> 
>             pool.returnObject(one.obj);
> 
>             /* Uncomment this for a progress indication
>             if (i % 10 == 0) {
>                 System.out.println(i/10);
>             }
>             */
>         }
>     }
> 
>     /**
>      * POOL-189
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockClosePool() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         Object obj1 = pool.borrowObject();
> 
>         // Make sure an object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
> 
>         // close the pool (Bug POOL-189)
>         pool.close();
> 
>         // Give interrupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>     }
> 
>     private class ConcurrentBorrowAndEvictThread extends Thread {
>         private boolean borrow;
>         public String obj;
> 
>         public ConcurrentBorrowAndEvictThread(boolean borrow) {
>             this.borrow = borrow;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 if (borrow) {
>                     obj = pool.borrowObject();
>                 } else {
>                     pool.evict();
>                 }
>             } catch (Exception e) { /* Ignore */}
>         }
>     }
> 
>     static class TestThread implements Runnable {
>         private final java.util.Random _random = new java.util.Random();
> 
>         // Thread config items
>         private final ObjectPool<String> _pool;
>         private final int _iter;
>         private final int _delay;
>         private final boolean _randomDelay;
>         private final Object _expectedObject;
> 
>         private volatile boolean _complete = false;
>         private volatile boolean _failed = false;
>         private volatile Throwable _error;
> 
>         public TestThread(ObjectPool<String> pool) {
>             this(pool, 100, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter) {
>             this(pool, iter, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay) {
>             this(pool, iter, delay, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay) {
>             this(pool, iter, delay, randomDelay, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay, Object obj) {
>             _pool = pool;
>             _iter = iter;
>             _delay = delay;
>             _randomDelay = randomDelay;
>             _expectedObject = obj;
>         }
> 
>         public boolean complete() {
>             return _complete;
>         }
> 
>         public boolean failed() {
>             return _failed;
>         }
> 
>         @Override
>         public void run() {
>             for(int i=0;i<_iter;i++) {
>                 long delay =
>                     _randomDelay ? (long)_random.nextInt(_delay) : _delay;
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 String obj = null;
>                 try {
>                     obj = _pool.borrowObject();
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 if (_expectedObject != null && !_expectedObject.equals(obj)) {
>                     _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 try {
>                     _pool.returnObject(obj);
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>             }
>             _complete = true;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testFIFO() throws Exception {
>         String o = null;
>         pool.setLifo(false);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Oldest", "0", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Youngest", "2", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testLIFO() throws Exception {
>         String o = null;
>         pool.setLifo(true);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Youngest", "2", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Oldest", "0", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testAddObject() throws Exception {
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         pool.addObject();
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>         String obj = pool.borrowObject();
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         assertEquals("should be one active", 1, pool.getNumActive());
>         pool.returnObject(obj);
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>     }
> 
>     protected GenericObjectPool<String> pool = null;
> 
>     private SimpleFactory factory = null;
> 
>     private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
>         assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
>                 Boolean.valueOf(actual.getTestOnCreate()));
>         assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
>                 Boolean.valueOf(actual.getTestOnBorrow()));
>         assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
>                 Boolean.valueOf(actual.getTestOnReturn()));
>         assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
>                 Boolean.valueOf(actual.getTestWhileIdle()));
>         assertEquals("whenExhaustedAction",
>                 Boolean.valueOf(expected.getBlockWhenExhausted()),
>                 Boolean.valueOf(actual.getBlockWhenExhausted()));
>         assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
>         assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
>         assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
>         assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
>         assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
>         assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
>     }
> 
>     public static class SimpleFactory implements PooledObjectFactory<String> {
>         public SimpleFactory() {
>             this(true);
>         }
>         public SimpleFactory(boolean valid) {
>             this(valid,valid);
>         }
>         public SimpleFactory(boolean evalid, boolean ovalid) {
>             evenValid = evalid;
>             oddValid = ovalid;
>         }
>         public synchronized void setValid(boolean valid) {
>             setEvenValid(valid);
>             setOddValid(valid);
>         }
>         public synchronized void setEvenValid(boolean valid) {
>             evenValid = valid;
>         }
>         public synchronized void setOddValid(boolean valid) {
>             oddValid = valid;
>         }
>         public synchronized void setThrowExceptionOnPassivate(boolean bool) {
>             exceptionOnPassivate = bool;
>         }
>         public synchronized void setMaxTotal(int maxTotal) {
>             this.maxTotal = maxTotal;
>         }
>         public synchronized void setDestroyLatency(long destroyLatency) {
>             this.destroyLatency = destroyLatency;
>         }
>         public synchronized void setMakeLatency(long makeLatency) {
>             this.makeLatency = makeLatency;
>         }
>         public synchronized void setValidateLatency(long validateLatency) {
>             this.validateLatency = validateLatency;
>         }
>         @Override
>         public PooledObject<String> makeObject() {
>             final long waitLatency;
>             synchronized(this) {
>                 activeCount++;
>                 if (activeCount > maxTotal) {
>                     throw new IllegalStateException(
>                         "Too many active instances: " + activeCount);
>                 }
>                 waitLatency = makeLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             final int counter;
>             synchronized(this) {
>                 counter = makeCounter++;
>             }
>             return new DefaultPooledObject<String>(String.valueOf(counter));
>         }
>         @Override
>         public void destroyObject(PooledObject<String> obj) throws Exception {
>             final long waitLatency;
>             final boolean hurl;
>             synchronized(this) {
>                 waitLatency = destroyLatency;
>                 hurl = exceptionOnDestroy;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             synchronized(this) {
>                 activeCount--;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         @Override
>         public boolean validateObject(PooledObject<String> obj) {
>             final boolean validate;
>             final boolean evenTest;
>             final boolean oddTest;
>             final long waitLatency;
>             final int counter;
>             synchronized(this) {
>                 validate = enableValidation;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>                 waitLatency = validateLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             if (validate) {
>                 return counter%2 == 0 ? evenTest : oddTest;
>             }
>             else {
>                 return true;
>             }
>         }
>         @Override
>         public void activateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             final boolean evenTest;
>             final boolean oddTest;
>             final int counter;
>             synchronized(this) {
>                 hurl = exceptionOnActivate;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>             }
>             if (hurl) {
>                 if (!(counter%2 == 0 ? evenTest : oddTest)) {
>                     throw new Exception();
>                 }
>             }
>         }
>         @Override
>         public void passivateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             synchronized(this) {
>                 hurl = exceptionOnPassivate;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         int makeCounter = 0;
>         int validateCounter = 0;
>         int activeCount = 0;
>         boolean evenValid = true;
>         boolean oddValid = true;
>         boolean exceptionOnPassivate = false;
>         boolean exceptionOnActivate = false;
>         boolean exceptionOnDestroy = false;
>         boolean enableValidation = true;
>         long destroyLatency = 0;
>         long makeLatency = 0;
>         long validateLatency = 0;
>         int maxTotal = Integer.MAX_VALUE;
> 
>         public synchronized boolean isThrowExceptionOnActivate() {
>             return exceptionOnActivate;
>         }
> 
>         public synchronized void setThrowExceptionOnActivate(boolean b) {
>             exceptionOnActivate = b;
>         }
> 
>         public synchronized void setThrowExceptionOnDestroy(boolean b) {
>             exceptionOnDestroy = b;
>         }
> 
>         public synchronized boolean isValidationEnabled() {
>             return enableValidation;
>         }
> 
>         public synchronized void setValidationEnabled(boolean b) {
>             enableValidation = b;
>         }
> 
>         public synchronized int getMakeCounter() {
>             return makeCounter;
>         }
> 
>         private void doWait(long latency) {
>             try {
>                 Thread.sleep(latency);
>             } catch (InterruptedException ex) {
>                 // ignore
>             }
>         }
>     }
>     @Override
>     protected boolean isLifo() {
>         return true;
>     }
> 
>     @Override
>     protected boolean isFifo() {
>         return false;
>     }
> 
>     /*
>      * Note: This test relies on timing for correct execution. There *should* be
>      * enough margin for this to work correctly on most (all?) systems but be
>      * aware of this if you see a failure of this test.
>      */
>     @Test(timeout=60000)
>     public void testBorrowObjectFairness() {
> 
>         // Config
>         int numThreads = 30;
>         int maxTotal = 10;
> 
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
>             Thread t = new Thread(threads[i]);
>             t.start();
>             // Short delay to ensure threads start in correct order
>             try {
>                 Thread.sleep(50);
>             } catch (InterruptedException e) {
>                 fail(e.toString());
>             }
>         }
> 
>         // Wait for threads to finish
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     /**
>      * On first borrow, first object fails validation, second object is OK.
>      * Subsequent borrows are OK. This was POOL-152.
>      */
>     @Test(timeout=60000)
>     public void testBrokenFactoryShouldNotBlockPool() {
>         int maxTotal = 1;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTestOnBorrow(true);
> 
>         // First borrow object will need to create a new object which will fail
>         // validation.
>         String obj = null;
>         Exception ex = null;
>         factory.setValid(false);
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e) {
>             ex = e;
>         }
>         // Failure expected
>         assertNotNull(ex);
>         assertTrue(ex instanceof NoSuchElementException);
>         assertNull(obj);
> 
>         // Configure factory to create valid objects so subsequent borrows work
>         factory.setValid(true);
> 
>         // Subsequent borrows should be OK
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e1) {
>             fail();
>         }
>         assertNotNull(obj);
>         try {
>             pool.returnObject(obj);
>         } catch (Exception e) {
>             fail();
>         }
>     }
> 
>     /*
>      * Very simple test thread that just tries to borrow an object from
>      * the provided pool returns it after a wait
>      */
>     static class WaitingTestThread extends Thread {
>         private final GenericObjectPool<String> _pool;
>         private final long _pause;
>         private Throwable _thrown;
> 
>         private long preborrow; // just before borrow
>         private long postborrow; //  borrow returned
>         private long postreturn; // after object was returned
>         private long ended;
>         private String objectId;
> 
>         public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
>             _pool = pool;
>             _pause = pause;
>             _thrown = null;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 preborrow = System.currentTimeMillis();
>                 String obj = _pool.borrowObject();
>                 objectId = obj;
>                 postborrow = System.currentTimeMillis();
>                 Thread.sleep(_pause);
>                 _pool.returnObject(obj);
>                 postreturn = System.currentTimeMillis();
>             } catch (Exception e) {
>                 _thrown = e;
>             } finally{
>                 ended = System.currentTimeMillis();
>             }
>         }
>     }
> 
>     private static final boolean DISPLAY_THREAD_DETAILS=
>         Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
>     // To pass this to a Maven test, use:
>     // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
>     // @see http://jira.codehaus.org/browse/SUREFIRE-121
> 
>     /*
>      * Test multi-threaded pool access.
>      * Multiple threads, but maxTotal only allows half the threads to succeed.
>      *
>      * This test was prompted by Continuum build failures in the Commons DBCP test case:
>      * TestPerUserPoolDataSource.testMultipleThreads2()
>      * Let's see if the this fails on Continuum too!
>      */
>     @Test(timeout=60000)
>     public void testMaxWaitMultiThreaded() throws Exception {
>         final long maxWait = 500; // wait for connection
>         final long holdTime = 2 * maxWait; // how long to hold connection
>         final int threads = 10; // number of threads to grab the object initially
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(maxWait);
>         pool.setMaxTotal(threads);
>         // Create enough threads so half the threads will have to wait
>         WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
>         for(int i=0; i < wtt.length; i++){
>             wtt[i] = new WaitingTestThread(pool,holdTime);
>         }
>         long origin = System.currentTimeMillis()-1000;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].start();
>         }
>         int failed = 0;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].join();
>             if (wtt[i]._thrown != null){
>                 failed++;
>             }
>         }
>         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
>             System.out.println(
>                     "MaxWait: " + maxWait +
>                     " HoldTime: " + holdTime +
>                      " MaxTotal: " + threads +
>                     " Threads: " + wtt.length +
>                     " Failed: " + failed
>                     );
>             for(int i=0; i < wtt.length; i++){
>                 WaitingTestThread wt = wtt[i];
>                 System.out.println(
>                         "Preborrow: " + (wt.preborrow-origin) +
>                         " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
>                         " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
>                         " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
>                         " Ended: " + (wt.ended-origin) +
>                         " ObjId: " + wt.objectId
>                         );
>             }
>         }
>         assertEquals("Expected half the threads to fail",wtt.length/2,failed);
>     }
> 
>     /**
>      * Test the following scenario:
>      *   Thread 1 borrows an instance
>      *   Thread 2 starts to borrow another instance before thread 1 returns its instance
>      *   Thread 1 returns its instance while thread 2 is validating its newly created instance
>      * The test verifies that the instance created by Thread 2 is not leaked.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMakeConcurrentWithReturn() throws Exception {
>         pool.setTestOnBorrow(true);
>         factory.setValid(true);
>         // Borrow and return an instance, with a short wait
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
>         thread1.start();
>         Thread.sleep(50); // wait for validation to succeed
>         // Slow down validation and borrow an instance
>         factory.setValidateLatency(400);
>         String instance = pool.borrowObject();
>         // Now make sure that we have not leaked an instance
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
>         pool.returnObject(instance);
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle());
>     }
> 
>     /**
>      * Ensure the pool is registered.
>      */
>     @Test(timeout=60000)
>     public void testJmxRegistration() {
>         ObjectName oname = pool.getJmxName();
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(oname, null);
>         Assert.assertEquals(1, result.size());
>         pool.jmxUnregister();
> 
>         GenericObjectPoolConfig config = new GenericObjectPoolConfig();
>         config.setJmxEnabled(false);
>         GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
>         assertNull(poolWithoutJmx.getJmxName());
>         config.setJmxEnabled(true);
>         poolWithoutJmx.jmxUnregister();
> 
>         config.setJmxNameBase(null);
>         GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
>         assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a checked out object is
>      * invalidated.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testInvalidateFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(500);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance
>         String obj = pool.borrowObject();
>         // Launch another thread - will block, but fail in 500 ms
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
>         thread2.start();
>         // Invalidate the object borrowed by this thread - should allow thread2 to create
>         Thread.sleep(20);
>         pool.invalidateObject(obj);
>         Thread.sleep(600); // Wait for thread2 to timeout
>         if (thread2._thrown != null) {
>             fail(thread2._thrown.toString());
>         }
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a returning object fails
>      * validation.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testValidationFailureOnReturnFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         factory.setValid(false); // Validate will always fail
>         factory.setValidationEnabled(true);
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(1500);
>         pool.setTestOnReturn(true);
>         pool.setTestOnBorrow(false);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance and return it after 500 ms (validation will fail)
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
>         thread2.start();
>         Thread.sleep(50);
>         // Try to borrow an object
>         String obj = pool.borrowObject();
>         pool.returnObject(obj);
>     }
> 
>     @Test
>     public void testSwallowedExceptionListener() {
>         pool.setSwallowedExceptionListener(null); // must simply return
>         final List<Exception> swallowedExceptions = new ArrayList<Exception>();
>         /*
>          * A simple listener, that will throw a OOM on 3rd exception.
>          */
>         final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
>             @Override
>             public void onSwallowException(Exception e) {
>                 if (swallowedExceptions.size() == 2) {
>                     throw new OutOfMemoryError();
>                 } else {
>                     swallowedExceptions.add(e);
>                 }
>             }
>         };
>         pool.setSwallowedExceptionListener(listener);
> 
>         Exception e1 = new Exception();
>         Exception e2 = new ArrayIndexOutOfBoundsException();
> 
>         pool.swallowException(e1);
>         pool.swallowException(e2);
> 
>         try {
>             pool.swallowException(e1);
>             fail("Not supposed to get here");
>         } catch (OutOfMemoryError oom) {
>             // expected
>         }
> 
>         assertEquals(2, swallowedExceptions.size());
>     }
> 
>     // POOL-248
>     @Test(expected=IllegalStateException.class)
>     public void testMultipleReturnOfSameObject() throws Exception {
>         final GenericObjectPool<String> pool = new GenericObjectPool<String>(
>                 factory, new GenericObjectPoolConfig());
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         String obj = pool.borrowObject();
> 
>         Assert.assertEquals(1, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>     }
> 
>     private static final class DummyFactory
>             extends BasePooledObjectFactory<Object> {
>         @Override
>         public Object create() throws Exception {
>             return null;
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>     }
> 
> 
>     private static class InvalidFactory
>             extends BasePooledObjectFactory<Object> {
> 
>         @Override
>         public Object create() throws Exception {
>             return new Object();
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
> 
>         @Override
>         public boolean validateObject(PooledObject<Object> obj) {
>             try {
>                 Thread.sleep(1000);
>             } catch (InterruptedException e) {
>                 // Ignore
>             }
>             return false;
>         }
>     }
> 
>     private static class EvictionThread<T> extends Thread {
> 
>         private final GenericObjectPool<T> pool;
> 
>         public EvictionThread(GenericObjectPool<T> pool) {
>             this.pool = pool;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 pool.evict();
>             } catch (Exception e) {
>                 // Ignore
>             }
>         }
>     }
> }
> /*
>  * Licensed to the Apache Software Foundation (ASF) under one or more
>  * contributor license agreements.  See the NOTICE file distributed with
>  * this work for additional information regarding copyright ownership.
>  * The ASF licenses this file to You under the Apache License, Version 2.0
>  * (the "License"); you may not use this file except in compliance with
>  * the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing, software
>  * distributed under the License is distributed on an "AS IS" BASIS,
>  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  * See the License for the specific language governing permissions and
>  * limitations under the License.
>  */
> 
> package org.apache.commons.pool2.impl;
> 
> import static org.junit.Assert.assertEquals;
> import static org.junit.Assert.assertFalse;
> import static org.junit.Assert.assertNotNull;
> import static org.junit.Assert.assertNull;
> import static org.junit.Assert.assertTrue;
> import static org.junit.Assert.fail;
> 
> import java.lang.management.ManagementFactory;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.NoSuchElementException;
> import java.util.Random;
> import java.util.Set;
> import java.util.concurrent.atomic.AtomicInteger;
> 
> import javax.management.MBeanServer;
> import javax.management.ObjectName;
> 
> import org.apache.commons.pool2.BasePooledObjectFactory;
> import org.apache.commons.pool2.ObjectPool;
> import org.apache.commons.pool2.PoolUtils;
> import org.apache.commons.pool2.PooledObject;
> import org.apache.commons.pool2.PooledObjectFactory;
> import org.apache.commons.pool2.SwallowedExceptionListener;
> import org.apache.commons.pool2.TestBaseObjectPool;
> import org.apache.commons.pool2.VisitTracker;
> import org.apache.commons.pool2.VisitTrackerFactory;
> import org.junit.After;
> import org.junit.Assert;
> import org.junit.Before;
> import org.junit.Test;
> 
> /**
>  * @version $Revision: 1569016 $
>  */
> public class TestGenericObjectPool extends TestBaseObjectPool {
> 
>     @Override
>     protected ObjectPool<String> makeEmptyPool(int mincap) {
>        GenericObjectPool<String> mtPool =
>                new GenericObjectPool<String>(new SimpleFactory());
>        mtPool.setMaxTotal(mincap);
>        mtPool.setMaxIdle(mincap);
>        return mtPool;
>     }
> 
>     @Override
>     protected ObjectPool<Object> makeEmptyPool(
>             final PooledObjectFactory<Object> fac) {
>         return new GenericObjectPool<Object>(fac);
>     }
> 
>     @Override
>     protected Object getNthObject(int n) {
>         return String.valueOf(n);
>     }
> 
>     @Before
>     public void setUp() throws Exception {
>         factory = new SimpleFactory();
>         pool = new GenericObjectPool<String>(factory);
>     }
> 
>     @After
>     public void tearDown() throws Exception {
>         String poolName = pool.getJmxName().toString();
>         pool.clear();
>         pool.close();
>         pool = null;
>         factory = null;
> 
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(new ObjectName(
>                 "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
>         // There should be no registered pools at this point
>         int registeredPoolCount = result.size();
>         StringBuilder msg = new StringBuilder("Current pool is: ");
>         msg.append(poolName);
>         msg.append("  Still open pools are: ");
>         for (ObjectName name : result) {
>             // Clean these up ready for the next test
>             msg.append(name.toString());
>             msg.append(" created via\n");
>             msg.append(mbs.getAttribute(name, "CreationStackTrace"));
>             msg.append('\n');
>             mbs.unregisterMBean(name);
>         }
>         Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
>     }
> 
>     @Test(expected=IllegalArgumentException.class)
>     public void testConstructorNullFactory() {
>         // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
>         assertNotNull(new GenericObjectPool<String>(null));
>         // TODO this currently causes tearDown to report an error
>         // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
>     }
> 
>     @Test(timeout=60000)
>     public void testConstructors() throws Exception {
> 
>         // Make constructor arguments all different from defaults
>         int minIdle = 2;
>         long maxWait = 3;
>         int maxIdle = 4;
>         int maxTotal = 5;
>         long minEvictableIdleTimeMillis = 6;
>         int numTestsPerEvictionRun = 7;
>         boolean testOnBorrow = true;
>         boolean testOnReturn = true;
>         boolean testWhileIdle = true;
>         long timeBetweenEvictionRunsMillis = 8;
>         boolean blockWhenExhausted = false;
>         boolean lifo = false;
>         PooledObjectFactory<Object> dummyFactory = new DummyFactory();
>         GenericObjectPool<Object> dummyPool =
>                 new GenericObjectPool<Object>(dummyFactory);
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
>                 dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
>                 Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
> 
>         GenericObjectPoolConfig config =
>                 new GenericObjectPoolConfig();
>         config.setLifo(lifo);
>         config.setMaxIdle(maxIdle);
>         config.setMinIdle(minIdle);
>         config.setMaxTotal(maxTotal);
>         config.setMaxWaitMillis(maxWait);
>         config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
>         config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
>         config.setTestOnBorrow(testOnBorrow);
>         config.setTestOnReturn(testOnReturn);
>         config.setTestWhileIdle(testWhileIdle);
>         config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
>         config.setBlockWhenExhausted(blockWhenExhausted);
>         dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
>         assertEquals(maxIdle, dummyPool.getMaxIdle());
>         assertEquals(maxWait, dummyPool.getMaxWaitMillis());
>         assertEquals(minIdle, dummyPool.getMinIdle());
>         assertEquals(maxTotal, dummyPool.getMaxTotal());
>         assertEquals(minEvictableIdleTimeMillis,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(testOnBorrow),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(testOnReturn),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(testWhileIdle),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(timeBetweenEvictionRunsMillis,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(blockWhenExhausted),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedFail() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(false);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumIdle());
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlock() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(10L);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         pool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockInterupt() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         String obj1 = pool.borrowObject();
> 
>         // Make sure on object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>         wtt.interrupt();
> 
>         // Give interupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
> 
>         // Return object to the pool
>         pool.returnObject(obj1);
> 
>         // Bug POOL-162 - check there is now an object in the pool
>         pool.setMaxWaitMillis(10L);
>         String obj2 = null;
>         try {
>              obj2 = pool.borrowObject();
>             assertNotNull(obj2);
>         } catch(NoSuchElementException e) {
>             // Not expected
>             fail("NoSuchElementException not expected");
>         }
>         pool.returnObject(obj2);
>         pool.close();
> 
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictWhileEmpty() throws Exception {
>         pool.evict();
>         pool.evict();
>         pool.close();
>     }
> 
>     /**
>      * Tests addObject contention between ensureMinIdle triggered by
>      * the Evictor with minIdle &gt; 0 and borrowObject.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictAddObjects() throws Exception {
>         factory.setMakeLatency(300);
>         factory.setMaxTotal(2);
>         pool.setMaxTotal(2);
>         pool.setMinIdle(1);
>         pool.borrowObject(); // numActive = 1, numIdle = 0
>         // Create a test thread that will run once and try a borrow after
>         // 150ms fixed delay
>         TestThread borrower = new TestThread(pool, 1, 150, false);
>         Thread borrowerThread = new Thread(borrower);
>         // Set evictor to run in 100 ms - will create idle instance
>         pool.setTimeBetweenEvictionRunsMillis(100);
>         borrowerThread.start();  // Off to the races
>         borrowerThread.join();
>         assertTrue(!borrower.failed());
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictLIFO() throws Exception {
>         checkEvict(true);
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictFIFO() throws Exception {
>         checkEvict(false);
>     }
> 
>     private void checkEvict(boolean lifo) throws Exception {
>         // yea this is hairy but it tests all the code paths in GOP.evict()
>         pool.setSoftMinEvictableIdleTimeMillis(10);
>         pool.setMinIdle(2);
>         pool.setTestWhileIdle(true);
>         pool.setLifo(lifo);
>         PoolUtils.prefill(pool, 5);
>         pool.evict();
>         factory.setEvenValid(false);
>         factory.setOddValid(false);
>         factory.setThrowExceptionOnActivate(true);
>         pool.evict();
>         PoolUtils.prefill(pool, 5);
>         factory.setThrowExceptionOnActivate(false);
>         factory.setThrowExceptionOnPassivate(true);
>         pool.evict();
>         factory.setThrowExceptionOnPassivate(false);
>         factory.setEvenValid(true);
>         factory.setOddValid(true);
>         Thread.sleep(125);
>         pool.evict();
>         assertEquals(2, pool.getNumIdle());
>     }
> 
>     /**
>      * Test to make sure evictor visits least recently used objects first,
>      * regardless of FIFO/LIFO.
>      *
>      * JIRA: POOL-86
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictionOrder() throws Exception {
>         checkEvictionOrder(false);
>         tearDown();
>         setUp();
>         checkEvictionOrder(true);
>     }
> 
>     private void checkEvictionOrder(boolean lifo) throws Exception {
>         checkEvictionOrderPart1(lifo);
>         tearDown();
>         setUp();
>         checkEvictionOrderPart2(lifo);
>     }
> 
>     private void checkEvictionOrderPart1(boolean lifo) throws Exception {
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         // Order, oldest to youngest, is "0", "1", ...,"4"
>         pool.evict(); // Should evict "0" and "1"
>         Object obj = pool.borrowObject();
>         assertTrue("oldest not evicted", !obj.equals("0"));
>         assertTrue("second oldest not evicted", !obj.equals("1"));
>         // 2 should be next out for FIFO, 4 for LIFO
>         assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
>     }
> 
>     private void checkEvictionOrderPart2(boolean lifo) throws Exception {
>         // Two eviction runs in sequence
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         pool.evict(); // Should evict "0" and "1"
>         pool.evict(); // Should evict "2" and "3"
>         Object obj = pool.borrowObject();
>         assertEquals("Wrong instance remaining in pool", "4", obj);
>     }
> 
>     /**
>      * Verifies that the evictor visits objects in expected order
>      * and frequency.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testEvictorVisiting() throws Exception {
>         checkEvictorVisiting(true);
>         checkEvictorVisiting(false);
>     }
> 
>     private void checkEvictorVisiting(boolean lifo) throws Exception {
>         VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
>         GenericObjectPool<VisitTracker<Object>> trackerPool =
>                 new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(2);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // Visit oldest 2 - 0 and 1
>         VisitTracker<Object> obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         //  borrow, return, borrow, return
>         //  FIFO will move 0 and 1 to end
>         //  LIFO, 7 out, then in, then out, then in
>         trackerPool.evict();  // Should visit 2 and 3 in either case
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() >= 4) {
>                 assertEquals("Unexpected instance visited " + tracker.getId(),
>                         0, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         trackerFactory = new VisitTrackerFactory<Object>();
>         trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(3);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // 0, 1, 2
>         trackerPool.evict(); // 3, 4, 5
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         // borrow, return, borrow, return
>         //  FIFO 3,4,5,6,7,0,1,2
>         //  LIFO 7,6,5,4,3,2,1,0
>         // In either case, pointer should be at 6
>         trackerPool.evict();
>         // Should hit 6,7,0 - 0 for second time
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() != 0) {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         2, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
> 
>         // Randomly generate a pools with random numTests
>         // and make sure evictor cycles through elements appropriately
>         int[] smallPrimes = {2, 3, 5, 7};
>         Random random = new Random();
>         random.setSeed(System.currentTimeMillis());
>         for (int i = 0; i < 4; i++) {
>             for (int j = 0; j < 5; j++) {
>                 trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>                 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
>                 trackerPool.setMinEvictableIdleTimeMillis(-1);
>                 trackerPool.setTestWhileIdle(true);
>                 trackerPool.setLifo(lifo);
>                 trackerPool.setTestOnReturn(false);
>                 trackerPool.setTestOnBorrow(false);
>                 trackerPool.setMaxIdle(-1);
>                 int instanceCount = 10 + random.nextInt(20);
>                 trackerPool.setMaxTotal(instanceCount);
>                 for (int k = 0; k < instanceCount; k++) {
>                     trackerPool.addObject();
>                 }
> 
>                 // Execute a random number of evictor runs
>                 int runs = 10 + random.nextInt(50);
>                 for (int k = 0; k < runs; k++) {
>                     trackerPool.evict();
>                 }
> 
>                 // Number of times evictor should have cycled through the pool
>                 int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
>                         instanceCount;
> 
>                 // Look at elements and make sure they are visited cycleCount
>                 // or cycleCount + 1 times
>                 VisitTracker<Object> tracker = null;
>                 int visitCount = 0;
>                 for (int k = 0; k < instanceCount; k++) {
>                     tracker = trackerPool.borrowObject();
>                     assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
>                     visitCount = tracker.getValidateCount();
>                     assertTrue(visitCount >= cycleCount &&
>                             visitCount <= cycleCount + 1);
>                 }
>                 trackerPool.close();
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnPassivateDuringReturn() throws Exception {
>         String obj = pool.borrowObject();
>         factory.setThrowExceptionOnPassivate(true);
>         pool.returnObject(obj);
>         assertEquals(0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringBorrow() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnBorrow(true);
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail on next borrow attempt
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringReturn() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnReturn(true);
>         String obj1 = pool.borrowObject();
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testExceptionOnActivateDuringBorrow() throws Exception {
>         String obj1 = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         pool.returnObject(obj1);
>         pool.returnObject(obj2);
>         factory.setThrowExceptionOnActivate(true);
>         factory.setEvenValid(false);
>         // Activation will now throw every other time
>         // First attempt throws, but loop continues and second succeeds
>         String obj = pool.borrowObject();
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
>         factory.setValid(false);
>         // Validation will now fail on activation when borrowObject returns
>         // an idle instance, and then when attempting to create a new instance
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(0, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testNegativeMaxTotal() throws Exception {
>         pool.setMaxTotal(-1);
>         pool.setBlockWhenExhausted(false);
>         String obj = pool.borrowObject();
>         assertEquals(getNthObject(0),obj);
>         pool.returnObject(obj);
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdle() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(8);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxIdleZero() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(0);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals(0, pool.getNumIdle());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotal() throws Exception {
>         pool.setMaxTotal(3);
>         pool.setBlockWhenExhausted(false);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>         pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testTimeoutNoLeak() throws Exception {
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(10);
>         pool.setBlockWhenExhausted(true);
>         String obj = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         pool.returnObject(obj2);
>         pool.returnObject(obj);
> 
>         pool.borrowObject();
>         pool.borrowObject();
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalZero() throws Exception {
>         pool.setMaxTotal(0);
>         pool.setBlockWhenExhausted(false);
> 
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMaxTotalUnderLoad() {
>         // Config
>         int numThreads = 199; // And main thread makes a round 200.
>         int numIter = 20;
>         int delay = 25;
>         int maxTotal = 10;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             // Factor of 2 on iterations so main thread does work whilst other
>             // threads are running. Factor of 2 on delay so average delay for
>             // other threads == actual delay for main thread
>             threads[i] = new TestThread(pool, numIter * 2, delay * 2);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         // Give the threads a chance to start doing some work
>         try {
>             Thread.sleep(5000);
>         } catch(InterruptedException e) {
>             // ignored
>         }
> 
>         for (int i = 0; i < numIter; i++) {
>             String obj = null;
>             try {
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 obj = pool.borrowObject();
>                 // Under load, observed _numActive > _maxTotal
>                 if (pool.getNumActive() > pool.getMaxTotal()) {
>                     throw new IllegalStateException("Too many active objects");
>                 }
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             } catch (Exception e) {
>                 // Shouldn't happen
>                 e.printStackTrace();
>                 fail("Exception on borrow");
>             } finally {
>                 if (obj != null) {
>                     try {
>                         pool.returnObject(obj);
>                     } catch (Exception e) {
>                         // Ignore
>                     }
>                 }
>             }
>         }
> 
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testSettersAndGetters() throws Exception {
>         {
>             // The object receives an Exception during its creation to prevent
>             // memory leaks. See BaseGenericObjectPool constructor for more details.
>             assertTrue(false == "".equals(pool.getCreationStackTrace()));
>         }
>         {
>             assertEquals(0, pool.getBorrowedCount());
>         }
>         {
>             assertEquals(0, pool.getReturnedCount());
>         }
>         {
>             assertEquals(0, pool.getCreatedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByEvictorCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByBorrowValidationCount());
>         }
>         {
>             assertEquals(0, pool.getMeanActiveTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanIdleTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getNumIdle());
>         }
>         {
>             pool.setMaxTotal(123);
>             assertEquals(123,pool.getMaxTotal());
>         }
>         {
>             pool.setMaxIdle(12);
>             assertEquals(12,pool.getMaxIdle());
>         }
>         {
>             pool.setMaxWaitMillis(1234L);
>             assertEquals(1234L,pool.getMaxWaitMillis());
>         }
>         {
>             pool.setMinEvictableIdleTimeMillis(12345L);
>             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setNumTestsPerEvictionRun(11);
>             assertEquals(11,pool.getNumTestsPerEvictionRun());
>         }
>         {
>             pool.setTestOnBorrow(true);
>             assertTrue(pool.getTestOnBorrow());
>             pool.setTestOnBorrow(false);
>             assertTrue(!pool.getTestOnBorrow());
>         }
>         {
>             pool.setTestOnReturn(true);
>             assertTrue(pool.getTestOnReturn());
>             pool.setTestOnReturn(false);
>             assertTrue(!pool.getTestOnReturn());
>         }
>         {
>             pool.setTestWhileIdle(true);
>             assertTrue(pool.getTestWhileIdle());
>             pool.setTestWhileIdle(false);
>             assertTrue(!pool.getTestWhileIdle());
>         }
>         {
>             pool.setTimeBetweenEvictionRunsMillis(11235L);
>             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
>         }
>         {
>             pool.setSoftMinEvictableIdleTimeMillis(12135L);
>             assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setBlockWhenExhausted(true);
>             assertTrue(pool.getBlockWhenExhausted());
>             pool.setBlockWhenExhausted(false);
>             assertFalse(pool.getBlockWhenExhausted());
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testDefaultConfiguration() throws Exception {
>         assertConfiguration(new GenericObjectPoolConfig(),pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testSetConfig() throws Exception {
>         GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
>         assertConfiguration(expected,pool);
>         expected.setMaxTotal(2);
>         expected.setMaxIdle(3);
>         expected.setMaxWaitMillis(5L);
>         expected.setMinEvictableIdleTimeMillis(7L);
>         expected.setNumTestsPerEvictionRun(9);
>         expected.setTestOnCreate(true);
>         expected.setTestOnBorrow(true);
>         expected.setTestOnReturn(true);
>         expected.setTestWhileIdle(true);
>         expected.setTimeBetweenEvictionRunsMillis(11L);
>         expected.setBlockWhenExhausted(false);
>         pool.setConfig(expected);
>         assertConfiguration(expected,pool);
>     }
> 
>     @Test(timeout=60000)
>     public void testStartAndStopEvictor() throws Exception {
>         // set up pool without evictor
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(6);
>         pool.setMinEvictableIdleTimeMillis(100L);
> 
>         for(int j=0;j<2;j++) {
>             // populate the pool
>             {
>                 String[] active = new String[6];
>                 for(int i=0;i<6;i++) {
>                     active[i] = pool.borrowObject();
>                 }
>                 for(int i=0;i<6;i++) {
>                     pool.returnObject(active[i]);
>                 }
>             }
> 
>             // note that it stays populated
>             assertEquals("Should have 6 idle",6,pool.getNumIdle());
> 
>             // start the evictor
>             pool.setTimeBetweenEvictionRunsMillis(50L);
> 
>             // wait a second (well, .2 seconds)
>             try { Thread.sleep(200L); } catch(InterruptedException e) { }
> 
>             // assert that the evictor has cleared out the pool
>             assertEquals("Should have 0 idle",0,pool.getNumIdle());
> 
>             // stop the evictor
>             pool.startEvictor(0L);
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionWithNegativeNumTests() throws Exception {
>         // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(-2);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
> 
>         String[] active = new String[6];
>         for(int i=0;i<6;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<6;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     @Test(timeout=60000)
>     public void testEviction() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(100);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
> 
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
>     }
> 
>     public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {
> 
>         private AtomicInteger callCount = new AtomicInteger(0);
> 
>         @Override
>         public boolean evict(EvictionConfig config, PooledObject<T> underTest,
>                 int idleCount) {
>             if (callCount.incrementAndGet() > 1500) {
>                 return true;
>             } else {
>                 return false;
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionPolicy() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(500);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
> 
>         // ClassNotFoundException
>         try {
>             pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // InstantiationException
>         try {
>             pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         // IllegalAccessException
>         try {
>             pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
> 
>         pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
>         assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());
> 
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         // Eviction policy ignores first 1500 attempts to evict and then always
>         // evicts. After 1s, there should have been two runs of 500 tests so no
>         // evictions
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 500 idle", 500, pool.getNumIdle());
>         // A further 1s wasn't enough so allow 2s for the evictor to clear out
>         // all of the idle objects.
>         try { Thread.sleep(2000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 0 idle", 0, pool.getNumIdle());
>     }
> 
> 
>     @Test(timeout=60000)
>     public void testEvictionSoftMinIdle() throws Exception {
>         class TimeTest extends BasePooledObjectFactory<TimeTest> {
>             private final long createTime;
>             public TimeTest() {
>                 createTime = System.currentTimeMillis();
>             }
>             @Override
>             public TimeTest create() throws Exception {
>                 return new TimeTest();
>             }
>             @Override
>             public PooledObject<TimeTest> wrap(TimeTest value) {
>                 return new DefaultPooledObject<TimeTest>(value);
>             }
>             public long getCreateTime() {
>                 return createTime;
>             }
>         }
> 
>         GenericObjectPool<TimeTest> timePool =
>             new GenericObjectPool<TimeTest>(new TimeTest());
> 
>         timePool.setMaxIdle(5);
>         timePool.setMaxTotal(5);
>         timePool.setNumTestsPerEvictionRun(5);
>         timePool.setMinEvictableIdleTimeMillis(3000L);
>         timePool.setSoftMinEvictableIdleTimeMillis(1000L);
>         timePool.setMinIdle(2);
> 
>         TimeTest[] active = new TimeTest[5];
>         Long[] creationTime = new Long[5] ;
>         for(int i=0;i<5;i++) {
>             active[i] = timePool.borrowObject();
>             creationTime[i] = Long.valueOf((active[i]).getCreateTime());
>         }
> 
>         for(int i=0;i<5;i++) {
>             timePool.returnObject(active[i]);
>         }
> 
>         // Soft evict all but minIdle(2)
>         Thread.sleep(1500L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());
> 
>         // Hard evict the rest.
>         Thread.sleep(2000L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
>         timePool.close();
>     }
> 
>     @Test(timeout=60000)
>     public void testEvictionInvalid() throws Exception {
> 
>         final GenericObjectPool<Object> invalidFactoryPool =
>                 new GenericObjectPool<Object>(new InvalidFactory());
> 
>         invalidFactoryPool.setMaxIdle(1);
>         invalidFactoryPool.setMaxTotal(1);
>         invalidFactoryPool.setTestOnBorrow(false);
>         invalidFactoryPool.setTestOnReturn(false);
>         invalidFactoryPool.setTestWhileIdle(true);
>         invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
>         invalidFactoryPool.setNumTestsPerEvictionRun(1);
> 
>         Object p = invalidFactoryPool.borrowObject();
>         invalidFactoryPool.returnObject(p);
> 
>         // Run eviction in a separate thread
>         Thread t = new EvictionThread<Object>(invalidFactoryPool);
>         t.start();
> 
>         // Sleep to make sure evictor has started
>         Thread.sleep(300);
> 
>         try {
>             invalidFactoryPool.borrowObject(1);
>         } catch (NoSuchElementException nsee) {
>             // Ignore
>         }
> 
>         // Make sure evictor has finished
>         Thread.sleep(1000);
> 
>         // Should have an empty pool
>         assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
>         assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
>         invalidFactoryPool.close();
>     }
> 
>     /**
>      * POOL-231 - verify that concurrent invalidates of the same object do not
>      * corrupt pool destroyCount.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testConcurrentInvalidate() throws Exception {
>         // Get allObjects and idleObjects loaded with some instances
>         final int nObjects = 1000;
>         pool.setMaxTotal(nObjects);
>         pool.setMaxIdle(nObjects);
>         final String[] obj = new String[nObjects];
>         for (int i = 0; i < nObjects; i++) {
>             obj[i] = pool.borrowObject();
>         }
>         for (int i = 0; i < nObjects; i++) {
>             if (i % 2 == 0) {
>                 pool.returnObject(obj[i]);
>             }
>         }
>         final int nThreads = 20;
>         final int nIterations = 60;
>         final InvalidateThread[] threads = new InvalidateThread[nThreads];
>         // Randomly generated list of distinct invalidation targets
>         final ArrayList<Integer> targets = new ArrayList<Integer>();
>         final Random random = new Random();
>         for (int j = 0; j < nIterations; j++) {
>             // Get a random invalidation target
>             Integer targ = Integer.valueOf(random.nextInt(nObjects));
>             while (targets.contains(targ)) {
>                 targ = Integer.valueOf(random.nextInt(nObjects));
>             }
>             targets.add(targ);
>             // Launch nThreads threads all trying to invalidate the target
>             for (int i = 0; i < nThreads; i++) {
>                 threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
>             }
>             for (int i = 0; i < nThreads; i++) {
>                 new Thread(threads[i]).start();
>             }
>             boolean done = false;
>             while (!done) {
>                 done = true;
>                 for (int i = 0; i < nThreads; i++) {
>                     done = done && threads[i].complete();
>                 }
>                 Thread.sleep(100);
>             }
>         }
>         Assert.assertEquals(nIterations, pool.getDestroyedCount());
>     }
> 
>     /**
>      * Attempts to invalidate an object, swallowing IllegalStateException.
>      */
>     static class InvalidateThread implements Runnable {
>         private final String obj;
>         private final ObjectPool<String> pool;
>         private boolean done = false;
>         public InvalidateThread(ObjectPool<String> pool, String obj) {
>             this.obj = obj;
>             this.pool = pool;
>         }
>         @Override
>         public void run() {
>             try {
>                 pool.invalidateObject(obj);
>             } catch (IllegalStateException ex) {
>                 // Ignore
>             } catch (Exception ex) {
>                 Assert.fail("Unexpected exception " + ex.toString());
>             } finally {
>                 done = true;
>             }
>         }
>         public boolean complete() {
>             return done;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdle() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[5];
>         active[0] = pool.borrowObject();
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=1 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     @Test(timeout=60000)
>     public void testMinIdleMaxTotal() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         String[] active = new String[10];
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);
> 
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
> 
>         for(int i=0 ; i<10 ; i++) {
>             active[i] = pool.borrowObject();
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);
> 
>         for(int i=0 ; i<10 ; i++) {
>             pool.returnObject(active[i]);
>         }
> 
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
> 
>     /**
>      * Kicks off <numThreads> test threads, each of which will go through
>      * <iterations> borrow-return cycles with random delay times <= delay
>      * in between.
>      */
>     private void runTestThreads(int numThreads, int iterations, int delay) {
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool,iterations,delay);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testThreaded1() throws Exception {
>         pool.setMaxTotal(15);
>         pool.setMaxIdle(15);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(20, 100, 50);
>     }
> 
>     /**
>      * Verifies that maxTotal is not exceeded when factory destroyObject
>      * has high latency, testOnReturn is set and there is high incidence of
>      * validation failures.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMaxTotalInvariant() throws Exception {
>         int maxTotal = 15;
>         factory.setEvenValid(false);     // Every other validation fails
>         factory.setDestroyLatency(100);  // Destroy takes 100 ms
>         factory.setMaxTotal(maxTotal); // (makes - destroys) bound
>         factory.setValidationEnabled(true);
>         pool.setMaxTotal(maxTotal);
>         pool.setMaxIdle(-1);
>         pool.setTestOnReturn(true);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(5, 10, 50);
>     }
> 
>     @Test(timeout=60000)
>     public void testConcurrentBorrowAndEvict() throws Exception {
> 
>         pool.setMaxTotal(1);
>         pool.addObject();
> 
>         for( int i=0; i<5000; i++) {
>             ConcurrentBorrowAndEvictThread one =
>                     new ConcurrentBorrowAndEvictThread(true);
>             ConcurrentBorrowAndEvictThread two =
>                     new ConcurrentBorrowAndEvictThread(false);
> 
>             one.start();
>             two.start();
>             one.join();
>             two.join();
> 
>             pool.returnObject(one.obj);
> 
>             /* Uncomment this for a progress indication
>             if (i % 10 == 0) {
>                 System.out.println(i/10);
>             }
>             */
>         }
>     }
> 
>     /**
>      * POOL-189
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockClosePool() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         Object obj1 = pool.borrowObject();
> 
>         // Make sure an object was obtained
>         assertNotNull(obj1);
> 
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
> 
>         // close the pool (Bug POOL-189)
>         pool.close();
> 
>         // Give interrupt time to take effect
>         Thread.sleep(200);
> 
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>     }
> 
>     private class ConcurrentBorrowAndEvictThread extends Thread {
>         private boolean borrow;
>         public String obj;
> 
>         public ConcurrentBorrowAndEvictThread(boolean borrow) {
>             this.borrow = borrow;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 if (borrow) {
>                     obj = pool.borrowObject();
>                 } else {
>                     pool.evict();
>                 }
>             } catch (Exception e) { /* Ignore */}
>         }
>     }
> 
>     static class TestThread implements Runnable {
>         private final java.util.Random _random = new java.util.Random();
> 
>         // Thread config items
>         private final ObjectPool<String> _pool;
>         private final int _iter;
>         private final int _delay;
>         private final boolean _randomDelay;
>         private final Object _expectedObject;
> 
>         private volatile boolean _complete = false;
>         private volatile boolean _failed = false;
>         private volatile Throwable _error;
> 
>         public TestThread(ObjectPool<String> pool) {
>             this(pool, 100, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter) {
>             this(pool, iter, 50, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay) {
>             this(pool, iter, delay, true, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay) {
>             this(pool, iter, delay, randomDelay, null);
>         }
> 
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay, Object obj) {
>             _pool = pool;
>             _iter = iter;
>             _delay = delay;
>             _randomDelay = randomDelay;
>             _expectedObject = obj;
>         }
> 
>         public boolean complete() {
>             return _complete;
>         }
> 
>         public boolean failed() {
>             return _failed;
>         }
> 
>         @Override
>         public void run() {
>             for(int i=0;i<_iter;i++) {
>                 long delay =
>                     _randomDelay ? (long)_random.nextInt(_delay) : _delay;
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 String obj = null;
>                 try {
>                     obj = _pool.borrowObject();
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 if (_expectedObject != null && !_expectedObject.equals(obj)) {
>                     _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
> 
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 try {
>                     _pool.returnObject(obj);
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>             }
>             _complete = true;
>         }
>     }
> 
>     @Test(timeout=60000)
>     public void testFIFO() throws Exception {
>         String o = null;
>         pool.setLifo(false);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Oldest", "0", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Youngest", "2", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testLIFO() throws Exception {
>         String o = null;
>         pool.setLifo(true);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Youngest", "2", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Oldest", "0", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
> 
>     @Test(timeout=60000)
>     public void testAddObject() throws Exception {
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         pool.addObject();
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>         String obj = pool.borrowObject();
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         assertEquals("should be one active", 1, pool.getNumActive());
>         pool.returnObject(obj);
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>     }
> 
>     protected GenericObjectPool<String> pool = null;
> 
>     private SimpleFactory factory = null;
> 
>     private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
>         assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
>                 Boolean.valueOf(actual.getTestOnCreate()));
>         assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
>                 Boolean.valueOf(actual.getTestOnBorrow()));
>         assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
>                 Boolean.valueOf(actual.getTestOnReturn()));
>         assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
>                 Boolean.valueOf(actual.getTestWhileIdle()));
>         assertEquals("whenExhaustedAction",
>                 Boolean.valueOf(expected.getBlockWhenExhausted()),
>                 Boolean.valueOf(actual.getBlockWhenExhausted()));
>         assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
>         assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
>         assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
>         assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
>         assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
>         assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
>     }
> 
>     public static class SimpleFactory implements PooledObjectFactory<String> {
>         public SimpleFactory() {
>             this(true);
>         }
>         public SimpleFactory(boolean valid) {
>             this(valid,valid);
>         }
>         public SimpleFactory(boolean evalid, boolean ovalid) {
>             evenValid = evalid;
>             oddValid = ovalid;
>         }
>         public synchronized void setValid(boolean valid) {
>             setEvenValid(valid);
>             setOddValid(valid);
>         }
>         public synchronized void setEvenValid(boolean valid) {
>             evenValid = valid;
>         }
>         public synchronized void setOddValid(boolean valid) {
>             oddValid = valid;
>         }
>         public synchronized void setThrowExceptionOnPassivate(boolean bool) {
>             exceptionOnPassivate = bool;
>         }
>         public synchronized void setMaxTotal(int maxTotal) {
>             this.maxTotal = maxTotal;
>         }
>         public synchronized void setDestroyLatency(long destroyLatency) {
>             this.destroyLatency = destroyLatency;
>         }
>         public synchronized void setMakeLatency(long makeLatency) {
>             this.makeLatency = makeLatency;
>         }
>         public synchronized void setValidateLatency(long validateLatency) {
>             this.validateLatency = validateLatency;
>         }
>         @Override
>         public PooledObject<String> makeObject() {
>             final long waitLatency;
>             synchronized(this) {
>                 activeCount++;
>                 if (activeCount > maxTotal) {
>                     throw new IllegalStateException(
>                         "Too many active instances: " + activeCount);
>                 }
>                 waitLatency = makeLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             final int counter;
>             synchronized(this) {
>                 counter = makeCounter++;
>             }
>             return new DefaultPooledObject<String>(String.valueOf(counter));
>         }
>         @Override
>         public void destroyObject(PooledObject<String> obj) throws Exception {
>             final long waitLatency;
>             final boolean hurl;
>             synchronized(this) {
>                 waitLatency = destroyLatency;
>                 hurl = exceptionOnDestroy;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             synchronized(this) {
>                 activeCount--;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         @Override
>         public boolean validateObject(PooledObject<String> obj) {
>             final boolean validate;
>             final boolean evenTest;
>             final boolean oddTest;
>             final long waitLatency;
>             final int counter;
>             synchronized(this) {
>                 validate = enableValidation;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>                 waitLatency = validateLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             if (validate) {
>                 return counter%2 == 0 ? evenTest : oddTest;
>             }
>             else {
>                 return true;
>             }
>         }
>         @Override
>         public void activateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             final boolean evenTest;
>             final boolean oddTest;
>             final int counter;
>             synchronized(this) {
>                 hurl = exceptionOnActivate;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>             }
>             if (hurl) {
>                 if (!(counter%2 == 0 ? evenTest : oddTest)) {
>                     throw new Exception();
>                 }
>             }
>         }
>         @Override
>         public void passivateObject(PooledObject<String> obj) throws Exception {
>             final boolean hurl;
>             synchronized(this) {
>                 hurl = exceptionOnPassivate;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         int makeCounter = 0;
>         int validateCounter = 0;
>         int activeCount = 0;
>         boolean evenValid = true;
>         boolean oddValid = true;
>         boolean exceptionOnPassivate = false;
>         boolean exceptionOnActivate = false;
>         boolean exceptionOnDestroy = false;
>         boolean enableValidation = true;
>         long destroyLatency = 0;
>         long makeLatency = 0;
>         long validateLatency = 0;
>         int maxTotal = Integer.MAX_VALUE;
> 
>         public synchronized boolean isThrowExceptionOnActivate() {
>             return exceptionOnActivate;
>         }
> 
>         public synchronized void setThrowExceptionOnActivate(boolean b) {
>             exceptionOnActivate = b;
>         }
> 
>         public synchronized void setThrowExceptionOnDestroy(boolean b) {
>             exceptionOnDestroy = b;
>         }
> 
>         public synchronized boolean isValidationEnabled() {
>             return enableValidation;
>         }
> 
>         public synchronized void setValidationEnabled(boolean b) {
>             enableValidation = b;
>         }
> 
>         public synchronized int getMakeCounter() {
>             return makeCounter;
>         }
> 
>         private void doWait(long latency) {
>             try {
>                 Thread.sleep(latency);
>             } catch (InterruptedException ex) {
>                 // ignore
>             }
>         }
>     }
>     @Override
>     protected boolean isLifo() {
>         return true;
>     }
> 
>     @Override
>     protected boolean isFifo() {
>         return false;
>     }
> 
>     /*
>      * Note: This test relies on timing for correct execution. There *should* be
>      * enough margin for this to work correctly on most (all?) systems but be
>      * aware of this if you see a failure of this test.
>      */
>     @Test(timeout=60000)
>     public void testBorrowObjectFairness() {
> 
>         // Config
>         int numThreads = 30;
>         int maxTotal = 10;
> 
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
> 
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
>             Thread t = new Thread(threads[i]);
>             t.start();
>             // Short delay to ensure threads start in correct order
>             try {
>                 Thread.sleep(50);
>             } catch (InterruptedException e) {
>                 fail(e.toString());
>             }
>         }
> 
>         // Wait for threads to finish
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
> 
>     /**
>      * On first borrow, first object fails validation, second object is OK.
>      * Subsequent borrows are OK. This was POOL-152.
>      */
>     @Test(timeout=60000)
>     public void testBrokenFactoryShouldNotBlockPool() {
>         int maxTotal = 1;
> 
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTestOnBorrow(true);
> 
>         // First borrow object will need to create a new object which will fail
>         // validation.
>         String obj = null;
>         Exception ex = null;
>         factory.setValid(false);
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e) {
>             ex = e;
>         }
>         // Failure expected
>         assertNotNull(ex);
>         assertTrue(ex instanceof NoSuchElementException);
>         assertNull(obj);
> 
>         // Configure factory to create valid objects so subsequent borrows work
>         factory.setValid(true);
> 
>         // Subsequent borrows should be OK
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e1) {
>             fail();
>         }
>         assertNotNull(obj);
>         try {
>             pool.returnObject(obj);
>         } catch (Exception e) {
>             fail();
>         }
>     }
> 
>     /*
>      * Very simple test thread that just tries to borrow an object from
>      * the provided pool returns it after a wait
>      */
>     static class WaitingTestThread extends Thread {
>         private final GenericObjectPool<String> _pool;
>         private final long _pause;
>         private Throwable _thrown;
> 
>         private long preborrow; // just before borrow
>         private long postborrow; //  borrow returned
>         private long postreturn; // after object was returned
>         private long ended;
>         private String objectId;
> 
>         public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
>             _pool = pool;
>             _pause = pause;
>             _thrown = null;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 preborrow = System.currentTimeMillis();
>                 String obj = _pool.borrowObject();
>                 objectId = obj;
>                 postborrow = System.currentTimeMillis();
>                 Thread.sleep(_pause);
>                 _pool.returnObject(obj);
>                 postreturn = System.currentTimeMillis();
>             } catch (Exception e) {
>                 _thrown = e;
>             } finally{
>                 ended = System.currentTimeMillis();
>             }
>         }
>     }
> 
>     private static final boolean DISPLAY_THREAD_DETAILS=
>         Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
>     // To pass this to a Maven test, use:
>     // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
>     // @see http://jira.codehaus.org/browse/SUREFIRE-121
> 
>     /*
>      * Test multi-threaded pool access.
>      * Multiple threads, but maxTotal only allows half the threads to succeed.
>      *
>      * This test was prompted by Continuum build failures in the Commons DBCP test case:
>      * TestPerUserPoolDataSource.testMultipleThreads2()
>      * Let's see if the this fails on Continuum too!
>      */
>     @Test(timeout=60000)
>     public void testMaxWaitMultiThreaded() throws Exception {
>         final long maxWait = 500; // wait for connection
>         final long holdTime = 2 * maxWait; // how long to hold connection
>         final int threads = 10; // number of threads to grab the object initially
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(maxWait);
>         pool.setMaxTotal(threads);
>         // Create enough threads so half the threads will have to wait
>         WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
>         for(int i=0; i < wtt.length; i++){
>             wtt[i] = new WaitingTestThread(pool,holdTime);
>         }
>         long origin = System.currentTimeMillis()-1000;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].start();
>         }
>         int failed = 0;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].join();
>             if (wtt[i]._thrown != null){
>                 failed++;
>             }
>         }
>         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
>             System.out.println(
>                     "MaxWait: " + maxWait +
>                     " HoldTime: " + holdTime +
>                      " MaxTotal: " + threads +
>                     " Threads: " + wtt.length +
>                     " Failed: " + failed
>                     );
>             for(int i=0; i < wtt.length; i++){
>                 WaitingTestThread wt = wtt[i];
>                 System.out.println(
>                         "Preborrow: " + (wt.preborrow-origin) +
>                         " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
>                         " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
>                         " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
>                         " Ended: " + (wt.ended-origin) +
>                         " ObjId: " + wt.objectId
>                         );
>             }
>         }
>         assertEquals("Expected half the threads to fail",wtt.length/2,failed);
>     }
> 
>     /**
>      * Test the following scenario:
>      *   Thread 1 borrows an instance
>      *   Thread 2 starts to borrow another instance before thread 1 returns its instance
>      *   Thread 1 returns its instance while thread 2 is validating its newly created instance
>      * The test verifies that the instance created by Thread 2 is not leaked.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMakeConcurrentWithReturn() throws Exception {
>         pool.setTestOnBorrow(true);
>         factory.setValid(true);
>         // Borrow and return an instance, with a short wait
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
>         thread1.start();
>         Thread.sleep(50); // wait for validation to succeed
>         // Slow down validation and borrow an instance
>         factory.setValidateLatency(400);
>         String instance = pool.borrowObject();
>         // Now make sure that we have not leaked an instance
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
>         pool.returnObject(instance);
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle());
>     }
> 
>     /**
>      * Ensure the pool is registered.
>      */
>     @Test(timeout=60000)
>     public void testJmxRegistration() {
>         ObjectName oname = pool.getJmxName();
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(oname, null);
>         Assert.assertEquals(1, result.size());
>         pool.jmxUnregister();
> 
>         GenericObjectPoolConfig config = new GenericObjectPoolConfig();
>         config.setJmxEnabled(false);
>         GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
>         assertNull(poolWithoutJmx.getJmxName());
>         config.setJmxEnabled(true);
>         poolWithoutJmx.jmxUnregister();
> 
>         config.setJmxNameBase(null);
>         GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
>         assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a checked out object is
>      * invalidated.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testInvalidateFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(500);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance
>         String obj = pool.borrowObject();
>         // Launch another thread - will block, but fail in 500 ms
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
>         thread2.start();
>         // Invalidate the object borrowed by this thread - should allow thread2 to create
>         Thread.sleep(20);
>         pool.invalidateObject(obj);
>         Thread.sleep(600); // Wait for thread2 to timeout
>         if (thread2._thrown != null) {
>             fail(thread2._thrown.toString());
>         }
>     }
> 
>     /**
>      * Verify that threads waiting on a depleted pool get served when a returning object fails
>      * validation.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testValidationFailureOnReturnFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         factory.setValid(false); // Validate will always fail
>         factory.setValidationEnabled(true);
>         GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(1500);
>         pool.setTestOnReturn(true);
>         pool.setTestOnBorrow(false);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance and return it after 500 ms (validation will fail)
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
>         thread2.start();
>         Thread.sleep(50);
>         // Try to borrow an object
>         String obj = pool.borrowObject();
>         pool.returnObject(obj);
>     }
> 
>     @Test
>     public void testSwallowedExceptionListener() {
>         pool.setSwallowedExceptionListener(null); // must simply return
>         final List<Exception> swallowedExceptions = new ArrayList<Exception>();
>         /*
>          * A simple listener, that will throw a OOM on 3rd exception.
>          */
>         final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
>             @Override
>             public void onSwallowException(Exception e) {
>                 if (swallowedExceptions.size() == 2) {
>                     throw new OutOfMemoryError();
>                 } else {
>                     swallowedExceptions.add(e);
>                 }
>             }
>         };
>         pool.setSwallowedExceptionListener(listener);
> 
>         Exception e1 = new Exception();
>         Exception e2 = new ArrayIndexOutOfBoundsException();
> 
>         pool.swallowException(e1);
>         pool.swallowException(e2);
> 
>         try {
>             pool.swallowException(e1);
>             fail("Not supposed to get here");
>         } catch (OutOfMemoryError oom) {
>             // expected
>         }
> 
>         assertEquals(2, swallowedExceptions.size());
>     }
> 
>     // POOL-248
>     @Test(expected=IllegalStateException.class)
>     public void testMultipleReturnOfSameObject() throws Exception {
>         final GenericObjectPool<String> pool = new GenericObjectPool<String>(
>                 factory, new GenericObjectPoolConfig());
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         String obj = pool.borrowObject();
> 
>         Assert.assertEquals(1, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
> 
>         pool.returnObject(obj);
> 
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>     }
> 
>     private static final class DummyFactory
>             extends BasePooledObjectFactory<Object> {
>         @Override
>         public Object create() throws Exception {
>             return null;
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>     }
> 
> 
>     private static class InvalidFactory
>             extends BasePooledObjectFactory<Object> {
> 
>         @Override
>         public Object create() throws Exception {
>             return new Object();
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
> 
>         @Override
>         public boolean validateObject(PooledObject<Object> obj) {
>             try {
>                 Thread.sleep(1000);
>             } catch (InterruptedException e) {
>                 // Ignore
>             }
>             return false;
>         }
>     }
> 
>     private static class EvictionThread<T> extends Thread {
> 
>         private final GenericObjectPool<T> pool;
> 
>         public EvictionThread(GenericObjectPool<T> pool) {
>             this.pool = pool;
>         }
> 
>         @Override
>         public void run() {
>             try {
>                 pool.evict();
>             } catch (Exception e) {
>                 // Ignore
>             }
>         }
>     }
> }
> 
> Not sure of the meaning you are inferring with 'multiplexed'
> 
> Best of Luck in Brasil
> Martin 
> ______________________________________________ 
>  _____ _          _____             _          _____     ___ _                        _____               _     _   _         
> |_   _| |_ ___   |  _  |___ ___ ___| |_ ___   |   __|___|  _| |_ _ _ _ ___ ___ ___   |   __|___ _ _ ___ _| |___| |_|_|___ ___ 
>   | | |   | -_|  |     | . | .'|  _|   | -_|  |__   | . |  _|  _| | | | .'|  _| -_|  |   __| . | | |   | . | .'|  _| | . |   |
>   |_| |_|_|___|  |__|__|  _|__,|___|_|_|___|  |_____|___|_| |_| |_____|__,|_| |___|  |__|  |___|___|_|_|___|__,|_| |_|___|_|_|
>                        |_|                                                                                                    
> 
> 
> From: JLeskovar@telecomsys.com
> To: user@commons.apache.org
> Subject: Multiplexed connections in commons pool
> Date: Wed, 18 Jun 2014 23:07:44 +0000
> 
> 
> 
> 
> 
> 
> 
> 
> 
> Hi there,
>  
> I have an application that needs to perform connection pooling, with the proviso that it's okay - and actually preferable - for more than one client to checkout and use the same connection object from the pool. Ideally, I would also like
>  to limit the number of concurrent clients that are using a single connection object. I'm wondering what the best way to do this is. As a quick and dirty option, I suppose I could basically have my PooledObjectFactory return the same objects from makeObject(),
>  and manually keep track of objects from inside my implementation. Thoughts?
>  
> Cheers,
> James Leskovar
> 
> Software Engineer, Location Platforms
> TeleCommunication Systems, Inc.
> 
> 
> 
> [ Address : TCS, iC Enterprise 1, Innovation Campus, Squires Way, Nth Wollongong, NSW, 2500, Australia ]
> 
> [ Tel : +61 2 4221 2940 ] [ Fax : +61 2 4221 2901 ] 
> 
> [ Email : James.Leskovar@telecomsys.com ]
> 
>  
> 
> CONFIDENTIALITY NOTICE: The information contained in this message may be privileged and/or confidential. If you are not the intended recipient, or responsible for delivering this message to the intended recipient, any review, forwarding, dissemination, distribution or copying of this communication or any attachment(s) is strictly prohibited. If you have received this message in error, please notify the sender immediately, and delete it and all attachments from your computer and network.
>  		 	   		  
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
> For additional commands, e-mail: user-help@commons.apache.org
> 
 		 	   		  

RE: Multiplexed connections in commons pool

Posted by James Leskovar <JL...@telecomsys.com>.
Hi Martin,

Thanks for the unit test - I'll check it out.

> Not sure of the meaning you are inferring with 'multiplexed'

I'm basically after having multiple calls to borrowObject<T>() return the same object - up to a limit - so that multiple clients can concurrently perform operations on the one connection object. So something like:

borrowObject() call #1 => returns object 1
borrowObject() call #2 => returns object 1
borrowObject() call #3 => returns object 1
borrowObject() call #4 => returns object 2
borrowObject() call #5 => returns object 2
borrowObject() call #6 => returns object 2

etc..

Basically, I don't want to have too many open connections to a given remote service, and instead have just a few connections that multiple clients can use - i.e. have a 100 clients borrowObject()'ing over a limited number of connections.

Cheers,
James


-----Original Message-----
From: Martin Gainty [mailto:mgainty@hotmail.com] 
Sent: Thursday, 19 June 2014 10:14 AM
To: Commons Users List
Subject: RE: Multiplexed connections in commons pool

James-
There is a nice test-case in 2.2 apache-commons that covers (Max-timeout-per-connection) and max-connections you are seeking:
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.pool2.impl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.SwallowedExceptionListener;
import org.apache.commons.pool2.TestBaseObjectPool;
import org.apache.commons.pool2.VisitTracker;
import org.apache.commons.pool2.VisitTrackerFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @version $Revision: 1569016 $
 */
public class TestGenericObjectPool extends TestBaseObjectPool {

    @Override
    protected ObjectPool<String> makeEmptyPool(int mincap) {
       GenericObjectPool<String> mtPool =
               new GenericObjectPool<String>(new SimpleFactory());
       mtPool.setMaxTotal(mincap);
       mtPool.setMaxIdle(mincap);
       return mtPool;
    }

    @Override
    protected ObjectPool<Object> makeEmptyPool(
            final PooledObjectFactory<Object> fac) {
        return new GenericObjectPool<Object>(fac);
    }

    @Override
    protected Object getNthObject(int n) {
        return String.valueOf(n);
    }

    @Before
    public void setUp() throws Exception {
        factory = new SimpleFactory();
        pool = new GenericObjectPool<String>(factory);
    }

    @After
    public void tearDown() throws Exception {
        String poolName = pool.getJmxName().toString();
        pool.clear();
        pool.close();
        pool = null;
        factory = null;

        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(new ObjectName(
                "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
        // There should be no registered pools at this point
        int registeredPoolCount = result.size();
        StringBuilder msg = new StringBuilder("Current pool is: ");
        msg.append(poolName);
        msg.append("  Still open pools are: ");
        for (ObjectName name : result) {
            // Clean these up ready for the next test
            msg.append(name.toString());
            msg.append(" created via\n");
            msg.append(mbs.getAttribute(name, "CreationStackTrace"));
            msg.append('\n');
            mbs.unregisterMBean(name);
        }
        Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
    }

    @Test(expected=IllegalArgumentException.class)
    public void testConstructorNullFactory() {
        // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
        assertNotNull(new GenericObjectPool<String>(null));
        // TODO this currently causes tearDown to report an error
        // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
    }

    @Test(timeout=60000)
    public void testConstructors() throws Exception {

        // Make constructor arguments all different from defaults
        int minIdle = 2;
        long maxWait = 3;
        int maxIdle = 4;
        int maxTotal = 5;
        long minEvictableIdleTimeMillis = 6;
        int numTestsPerEvictionRun = 7;
        boolean testOnBorrow = true;
        boolean testOnReturn = true;
        boolean testWhileIdle = true;
        long timeBetweenEvictionRunsMillis = 8;
        boolean blockWhenExhausted = false;
        boolean lifo = false;
        PooledObjectFactory<Object> dummyFactory = new DummyFactory();
        GenericObjectPool<Object> dummyPool =
                new GenericObjectPool<Object>(dummyFactory);
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
                Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();

        GenericObjectPoolConfig config =
                new GenericObjectPoolConfig();
        config.setLifo(lifo);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWait);
        config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setTestWhileIdle(testWhileIdle);
        config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        config.setBlockWhenExhausted(blockWhenExhausted);
        dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
        assertEquals(maxIdle, dummyPool.getMaxIdle());
        assertEquals(maxWait, dummyPool.getMaxWaitMillis());
        assertEquals(minIdle, dummyPool.getMinIdle());
        assertEquals(maxTotal, dummyPool.getMaxTotal());
        assertEquals(minEvictableIdleTimeMillis,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(testOnBorrow),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(testOnReturn),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(testWhileIdle),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(timeBetweenEvictionRunsMillis,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(blockWhenExhausted),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedFail() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(false);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumIdle());
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlock() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(10L);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlockInterupt() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        String obj1 = pool.borrowObject();

        // Make sure on object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);
        wtt.interrupt();

        // Give interupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);

        // Return object to the pool
        pool.returnObject(obj1);

        // Bug POOL-162 - check there is now an object in the pool
        pool.setMaxWaitMillis(10L);
        String obj2 = null;
        try {
             obj2 = pool.borrowObject();
            assertNotNull(obj2);
        } catch(NoSuchElementException e) {
            // Not expected
            fail("NoSuchElementException not expected");
        }
        pool.returnObject(obj2);
        pool.close();

    }

    @Test(timeout=60000)
    public void testEvictWhileEmpty() throws Exception {
        pool.evict();
        pool.evict();
        pool.close();
    }

    /**
     * Tests addObject contention between ensureMinIdle triggered by
     * the Evictor with minIdle &gt; 0 and borrowObject.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictAddObjects() throws Exception {
        factory.setMakeLatency(300);
        factory.setMaxTotal(2);
        pool.setMaxTotal(2);
        pool.setMinIdle(1);
        pool.borrowObject(); // numActive = 1, numIdle = 0
        // Create a test thread that will run once and try a borrow after
        // 150ms fixed delay
        TestThread borrower = new TestThread(pool, 1, 150, false);
        Thread borrowerThread = new Thread(borrower);
        // Set evictor to run in 100 ms - will create idle instance
        pool.setTimeBetweenEvictionRunsMillis(100);
        borrowerThread.start();  // Off to the races
        borrowerThread.join();
        assertTrue(!borrower.failed());
    }

    @Test(timeout=60000)
    public void testEvictLIFO() throws Exception {
        checkEvict(true);
    }

    @Test(timeout=60000)
    public void testEvictFIFO() throws Exception {
        checkEvict(false);
    }

    private void checkEvict(boolean lifo) throws Exception {
        // yea this is hairy but it tests all the code paths in GOP.evict()
        pool.setSoftMinEvictableIdleTimeMillis(10);
        pool.setMinIdle(2);
        pool.setTestWhileIdle(true);
        pool.setLifo(lifo);
        PoolUtils.prefill(pool, 5);
        pool.evict();
        factory.setEvenValid(false);
        factory.setOddValid(false);
        factory.setThrowExceptionOnActivate(true);
        pool.evict();
        PoolUtils.prefill(pool, 5);
        factory.setThrowExceptionOnActivate(false);
        factory.setThrowExceptionOnPassivate(true);
        pool.evict();
        factory.setThrowExceptionOnPassivate(false);
        factory.setEvenValid(true);
        factory.setOddValid(true);
        Thread.sleep(125);
        pool.evict();
        assertEquals(2, pool.getNumIdle());
    }

    /**
     * Test to make sure evictor visits least recently used objects first,
     * regardless of FIFO/LIFO.
     *
     * JIRA: POOL-86
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictionOrder() throws Exception {
        checkEvictionOrder(false);
        tearDown();
        setUp();
        checkEvictionOrder(true);
    }

    private void checkEvictionOrder(boolean lifo) throws Exception {
        checkEvictionOrderPart1(lifo);
        tearDown();
        setUp();
        checkEvictionOrderPart2(lifo);
    }

    private void checkEvictionOrderPart1(boolean lifo) throws Exception {
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        // Order, oldest to youngest, is "0", "1", ...,"4"
        pool.evict(); // Should evict "0" and "1"
        Object obj = pool.borrowObject();
        assertTrue("oldest not evicted", !obj.equals("0"));
        assertTrue("second oldest not evicted", !obj.equals("1"));
        // 2 should be next out for FIFO, 4 for LIFO
        assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
    }

    private void checkEvictionOrderPart2(boolean lifo) throws Exception {
        // Two eviction runs in sequence
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        pool.evict(); // Should evict "0" and "1"
        pool.evict(); // Should evict "2" and "3"
        Object obj = pool.borrowObject();
        assertEquals("Wrong instance remaining in pool", "4", obj);
    }

    /**
     * Verifies that the evictor visits objects in expected order
     * and frequency.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testEvictorVisiting() throws Exception {
        checkEvictorVisiting(true);
        checkEvictorVisiting(false);
    }

    private void checkEvictorVisiting(boolean lifo) throws Exception {
        VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
        GenericObjectPool<VisitTracker<Object>> trackerPool =
                new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(2);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // Visit oldest 2 - 0 and 1
        VisitTracker<Object> obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        //  borrow, return, borrow, return
        //  FIFO will move 0 and 1 to end
        //  LIFO, 7 out, then in, then out, then in
        trackerPool.evict();  // Should visit 2 and 3 in either case
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() >= 4) {
                assertEquals("Unexpected instance visited " + tracker.getId(),
                        0, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        trackerFactory = new VisitTrackerFactory<Object>();
        trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(3);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // 0, 1, 2
        trackerPool.evict(); // 3, 4, 5
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        // borrow, return, borrow, return
        //  FIFO 3,4,5,6,7,0,1,2
        //  LIFO 7,6,5,4,3,2,1,0
        // In either case, pointer should be at 6
        trackerPool.evict();
        // Should hit 6,7,0 - 0 for second time
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() != 0) {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        2, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        // Randomly generate a pools with random numTests
        // and make sure evictor cycles through elements appropriately
        int[] smallPrimes = {2, 3, 5, 7};
        Random random = new Random();
        random.setSeed(System.currentTimeMillis());
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 5; j++) {
                trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
                trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
                trackerPool.setMinEvictableIdleTimeMillis(-1);
                trackerPool.setTestWhileIdle(true);
                trackerPool.setLifo(lifo);
                trackerPool.setTestOnReturn(false);
                trackerPool.setTestOnBorrow(false);
                trackerPool.setMaxIdle(-1);
                int instanceCount = 10 + random.nextInt(20);
                trackerPool.setMaxTotal(instanceCount);
                for (int k = 0; k < instanceCount; k++) {
                    trackerPool.addObject();
                }

                // Execute a random number of evictor runs
                int runs = 10 + random.nextInt(50);
                for (int k = 0; k < runs; k++) {
                    trackerPool.evict();
                }

                // Number of times evictor should have cycled through the pool
                int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
                        instanceCount;

                // Look at elements and make sure they are visited cycleCount
                // or cycleCount + 1 times
                VisitTracker<Object> tracker = null;
                int visitCount = 0;
                for (int k = 0; k < instanceCount; k++) {
                    tracker = trackerPool.borrowObject();
                    assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
                    visitCount = tracker.getValidateCount();
                    assertTrue(visitCount >= cycleCount &&
                            visitCount <= cycleCount + 1);
                }
                trackerPool.close();
            }
        }
    }

    @Test(timeout=60000)
    public void testExceptionOnPassivateDuringReturn() throws Exception {
        String obj = pool.borrowObject();
        factory.setThrowExceptionOnPassivate(true);
        pool.returnObject(obj);
        assertEquals(0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringBorrow() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnBorrow(true);
        pool.borrowObject();
        factory.setValid(false); // Make validation fail on next borrow attempt
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringReturn() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnReturn(true);
        String obj1 = pool.borrowObject();
        pool.borrowObject();
        factory.setValid(false); // Make validation fail
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnActivateDuringBorrow() throws Exception {
        String obj1 = pool.borrowObject();
        String obj2 = pool.borrowObject();
        pool.returnObject(obj1);
        pool.returnObject(obj2);
        factory.setThrowExceptionOnActivate(true);
        factory.setEvenValid(false);
        // Activation will now throw every other time
        // First attempt throws, but loop continues and second succeeds
        String obj = pool.borrowObject();
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);
        factory.setValid(false);
        // Validation will now fail on activation when borrowObject returns
        // an idle instance, and then when attempting to create a new instance
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(0, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testNegativeMaxTotal() throws Exception {
        pool.setMaxTotal(-1);
        pool.setBlockWhenExhausted(false);
        String obj = pool.borrowObject();
        assertEquals(getNthObject(0),obj);
        pool.returnObject(obj);
    }

    @Test(timeout=60000)
    public void testMaxIdle() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(8);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxIdleZero() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(0);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals(0, pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxTotal() throws Exception {
        pool.setMaxTotal(3);
        pool.setBlockWhenExhausted(false);

        pool.borrowObject();
        pool.borrowObject();
        pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testTimeoutNoLeak() throws Exception {
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(10);
        pool.setBlockWhenExhausted(true);
        String obj = pool.borrowObject();
        String obj2 = pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        pool.returnObject(obj2);
        pool.returnObject(obj);

        pool.borrowObject();
        pool.borrowObject();
    }

    @Test(timeout=60000)
    public void testMaxTotalZero() throws Exception {
        pool.setMaxTotal(0);
        pool.setBlockWhenExhausted(false);

        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testMaxTotalUnderLoad() {
        // Config
        int numThreads = 199; // And main thread makes a round 200.
        int numIter = 20;
        int delay = 25;
        int maxTotal = 10;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            // Factor of 2 on iterations so main thread does work whilst other
            // threads are running. Factor of 2 on delay so average delay for
            // other threads == actual delay for main thread
            threads[i] = new TestThread(pool, numIter * 2, delay * 2);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        // Give the threads a chance to start doing some work
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) {
            // ignored
        }

        for (int i = 0; i < numIter; i++) {
            String obj = null;
            try {
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                obj = pool.borrowObject();
                // Under load, observed _numActive > _maxTotal
                if (pool.getNumActive() > pool.getMaxTotal()) {
                    throw new IllegalStateException("Too many active objects");
                }
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
            } catch (Exception e) {
                // Shouldn't happen
                e.printStackTrace();
                fail("Exception on borrow");
            } finally {
                if (obj != null) {
                    try {
                        pool.returnObject(obj);
                    } catch (Exception e) {
                        // Ignore
                    }
                }
            }
        }

        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testSettersAndGetters() throws Exception {
        {
            // The object receives an Exception during its creation to prevent
            // memory leaks. See BaseGenericObjectPool constructor for more details.
            assertTrue(false == "".equals(pool.getCreationStackTrace()));
        }
        {
            assertEquals(0, pool.getBorrowedCount());
        }
        {
            assertEquals(0, pool.getReturnedCount());
        }
        {
            assertEquals(0, pool.getCreatedCount());
        }
        {
            assertEquals(0, pool.getDestroyedCount());
        }
        {
            assertEquals(0, pool.getDestroyedByEvictorCount());
        }
        {
            assertEquals(0, pool.getDestroyedByBorrowValidationCount());
        }
        {
            assertEquals(0, pool.getMeanActiveTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanIdleTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getNumIdle());
        }
        {
            pool.setMaxTotal(123);
            assertEquals(123,pool.getMaxTotal());
        }
        {
            pool.setMaxIdle(12);
            assertEquals(12,pool.getMaxIdle());
        }
        {
            pool.setMaxWaitMillis(1234L);
            assertEquals(1234L,pool.getMaxWaitMillis());
        }
        {
            pool.setMinEvictableIdleTimeMillis(12345L);
            assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
        }
        {
            pool.setNumTestsPerEvictionRun(11);
            assertEquals(11,pool.getNumTestsPerEvictionRun());
        }
        {
            pool.setTestOnBorrow(true);
            assertTrue(pool.getTestOnBorrow());
            pool.setTestOnBorrow(false);
            assertTrue(!pool.getTestOnBorrow());
        }
        {
            pool.setTestOnReturn(true);
            assertTrue(pool.getTestOnReturn());
            pool.setTestOnReturn(false);
            assertTrue(!pool.getTestOnReturn());
        }
        {
            pool.setTestWhileIdle(true);
            assertTrue(pool.getTestWhileIdle());
            pool.setTestWhileIdle(false);
            assertTrue(!pool.getTestWhileIdle());
        }
        {
            pool.setTimeBetweenEvictionRunsMillis(11235L);
            assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
        }
        {
            pool.setSoftMinEvictableIdleTimeMillis(12135L);
            assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
        }
        {
            pool.setBlockWhenExhausted(true);
            assertTrue(pool.getBlockWhenExhausted());
            pool.setBlockWhenExhausted(false);
            assertFalse(pool.getBlockWhenExhausted());
        }
    }

    @Test(timeout=60000)
    public void testDefaultConfiguration() throws Exception {
        assertConfiguration(new GenericObjectPoolConfig(),pool);
    }

    @Test(timeout=60000)
    public void testSetConfig() throws Exception {
        GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
        assertConfiguration(expected,pool);
        expected.setMaxTotal(2);
        expected.setMaxIdle(3);
        expected.setMaxWaitMillis(5L);
        expected.setMinEvictableIdleTimeMillis(7L);
        expected.setNumTestsPerEvictionRun(9);
        expected.setTestOnCreate(true);
        expected.setTestOnBorrow(true);
        expected.setTestOnReturn(true);
        expected.setTestWhileIdle(true);
        expected.setTimeBetweenEvictionRunsMillis(11L);
        expected.setBlockWhenExhausted(false);
        pool.setConfig(expected);
        assertConfiguration(expected,pool);
    }

    @Test(timeout=60000)
    public void testStartAndStopEvictor() throws Exception {
        // set up pool without evictor
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(6);
        pool.setMinEvictableIdleTimeMillis(100L);

        for(int j=0;j<2;j++) {
            // populate the pool
            {
                String[] active = new String[6];
                for(int i=0;i<6;i++) {
                    active[i] = pool.borrowObject();
                }
                for(int i=0;i<6;i++) {
                    pool.returnObject(active[i]);
                }
            }

            // note that it stays populated
            assertEquals("Should have 6 idle",6,pool.getNumIdle());

            // start the evictor
            pool.setTimeBetweenEvictionRunsMillis(50L);

            // wait a second (well, .2 seconds)
            try { Thread.sleep(200L); } catch(InterruptedException e) { }

            // assert that the evictor has cleared out the pool
            assertEquals("Should have 0 idle",0,pool.getNumIdle());

            // stop the evictor
            pool.startEvictor(0L);
        }
    }

    @Test(timeout=60000)
    public void testEvictionWithNegativeNumTests() throws Exception {
        // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(-2);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);

        String[] active = new String[6];
        for(int i=0;i<6;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<6;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testEviction() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(100);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());

        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {

        private AtomicInteger callCount = new AtomicInteger(0);

        @Override
        public boolean evict(EvictionConfig config, PooledObject<T> underTest,
                int idleCount) {
            if (callCount.incrementAndGet() > 1500) {
                return true;
            } else {
                return false;
            }
        }
    }

    @Test(timeout=60000)
    public void testEvictionPolicy() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(500);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        // ClassNotFoundException
        try {
            pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // InstantiationException
        try {
            pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // IllegalAccessException
        try {
            pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
        assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        // Eviction policy ignores first 1500 attempts to evict and then always
        // evicts. After 1s, there should have been two runs of 500 tests so no
        // evictions
        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertEquals("Should be 500 idle", 500, pool.getNumIdle());
        // A further 1s wasn't enough so allow 2s for the evictor to clear out
        // all of the idle objects.
        try { Thread.sleep(2000L); } catch(InterruptedException e) { }
        assertEquals("Should be 0 idle", 0, pool.getNumIdle());
    }


    @Test(timeout=60000)
    public void testEvictionSoftMinIdle() throws Exception {
        class TimeTest extends BasePooledObjectFactory<TimeTest> {
            private final long createTime;
            public TimeTest() {
                createTime = System.currentTimeMillis();
            }
            @Override
            public TimeTest create() throws Exception {
                return new TimeTest();
            }
            @Override
            public PooledObject<TimeTest> wrap(TimeTest value) {
                return new DefaultPooledObject<TimeTest>(value);
            }
            public long getCreateTime() {
                return createTime;
            }
        }

        GenericObjectPool<TimeTest> timePool =
            new GenericObjectPool<TimeTest>(new TimeTest());

        timePool.setMaxIdle(5);
        timePool.setMaxTotal(5);
        timePool.setNumTestsPerEvictionRun(5);
        timePool.setMinEvictableIdleTimeMillis(3000L);
        timePool.setSoftMinEvictableIdleTimeMillis(1000L);
        timePool.setMinIdle(2);

        TimeTest[] active = new TimeTest[5];
        Long[] creationTime = new Long[5] ;
        for(int i=0;i<5;i++) {
            active[i] = timePool.borrowObject();
            creationTime[i] = Long.valueOf((active[i]).getCreateTime());
        }

        for(int i=0;i<5;i++) {
            timePool.returnObject(active[i]);
        }

        // Soft evict all but minIdle(2)
        Thread.sleep(1500L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());

        // Hard evict the rest.
        Thread.sleep(2000L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
        timePool.close();
    }

    @Test(timeout=60000)
    public void testEvictionInvalid() throws Exception {

        final GenericObjectPool<Object> invalidFactoryPool =
                new GenericObjectPool<Object>(new InvalidFactory());

        invalidFactoryPool.setMaxIdle(1);
        invalidFactoryPool.setMaxTotal(1);
        invalidFactoryPool.setTestOnBorrow(false);
        invalidFactoryPool.setTestOnReturn(false);
        invalidFactoryPool.setTestWhileIdle(true);
        invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
        invalidFactoryPool.setNumTestsPerEvictionRun(1);

        Object p = invalidFactoryPool.borrowObject();
        invalidFactoryPool.returnObject(p);

        // Run eviction in a separate thread
        Thread t = new EvictionThread<Object>(invalidFactoryPool);
        t.start();

        // Sleep to make sure evictor has started
        Thread.sleep(300);

        try {
            invalidFactoryPool.borrowObject(1);
        } catch (NoSuchElementException nsee) {
            // Ignore
        }

        // Make sure evictor has finished
        Thread.sleep(1000);

        // Should have an empty pool
        assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
        assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
        invalidFactoryPool.close();
    }

    /**
     * POOL-231 - verify that concurrent invalidates of the same object do not
     * corrupt pool destroyCount.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testConcurrentInvalidate() throws Exception {
        // Get allObjects and idleObjects loaded with some instances
        final int nObjects = 1000;
        pool.setMaxTotal(nObjects);
        pool.setMaxIdle(nObjects);
        final String[] obj = new String[nObjects];
        for (int i = 0; i < nObjects; i++) {
            obj[i] = pool.borrowObject();
        }
        for (int i = 0; i < nObjects; i++) {
            if (i % 2 == 0) {
                pool.returnObject(obj[i]);
            }
        }
        final int nThreads = 20;
        final int nIterations = 60;
        final InvalidateThread[] threads = new InvalidateThread[nThreads];
        // Randomly generated list of distinct invalidation targets
        final ArrayList<Integer> targets = new ArrayList<Integer>();
        final Random random = new Random();
        for (int j = 0; j < nIterations; j++) {
            // Get a random invalidation target
            Integer targ = Integer.valueOf(random.nextInt(nObjects));
            while (targets.contains(targ)) {
                targ = Integer.valueOf(random.nextInt(nObjects));
            }
            targets.add(targ);
            // Launch nThreads threads all trying to invalidate the target
            for (int i = 0; i < nThreads; i++) {
                threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
            }
            for (int i = 0; i < nThreads; i++) {
                new Thread(threads[i]).start();
            }
            boolean done = false;
            while (!done) {
                done = true;
                for (int i = 0; i < nThreads; i++) {
                    done = done && threads[i].complete();
                }
                Thread.sleep(100);
            }
        }
        Assert.assertEquals(nIterations, pool.getDestroyedCount());
    }

    /**
     * Attempts to invalidate an object, swallowing IllegalStateException.
     */
    static class InvalidateThread implements Runnable {
        private final String obj;
        private final ObjectPool<String> pool;
        private boolean done = false;
        public InvalidateThread(ObjectPool<String> pool, String obj) {
            this.obj = obj;
            this.pool = pool;
        }
        @Override
        public void run() {
            try {
                pool.invalidateObject(obj);
            } catch (IllegalStateException ex) {
                // Ignore
            } catch (Exception ex) {
                Assert.fail("Unexpected exception " + ex.toString());
            } finally {
                done = true;
            }
        }
        public boolean complete() {
            return done;
        }
    }

    @Test(timeout=60000)
    public void testMinIdle() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[5];
        active[0] = pool.borrowObject();

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=1 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    @Test(timeout=60000)
    public void testMinIdleMaxTotal() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[10];

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);

        for(int i=0 ; i<10 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);

        for(int i=0 ; i<10 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    /**
     * Kicks off <numThreads> test threads, each of which will go through
     * <iterations> borrow-return cycles with random delay times <= delay
     * in between.
     */
    private void runTestThreads(int numThreads, int iterations, int delay) {
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool,iterations,delay);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testThreaded1() throws Exception {
        pool.setMaxTotal(15);
        pool.setMaxIdle(15);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(20, 100, 50);
    }

    /**
     * Verifies that maxTotal is not exceeded when factory destroyObject
     * has high latency, testOnReturn is set and there is high incidence of
     * validation failures.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMaxTotalInvariant() throws Exception {
        int maxTotal = 15;
        factory.setEvenValid(false);     // Every other validation fails
        factory.setDestroyLatency(100);  // Destroy takes 100 ms
        factory.setMaxTotal(maxTotal); // (makes - destroys) bound
        factory.setValidationEnabled(true);
        pool.setMaxTotal(maxTotal);
        pool.setMaxIdle(-1);
        pool.setTestOnReturn(true);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(5, 10, 50);
    }

    @Test(timeout=60000)
    public void testConcurrentBorrowAndEvict() throws Exception {

        pool.setMaxTotal(1);
        pool.addObject();

        for( int i=0; i<5000; i++) {
            ConcurrentBorrowAndEvictThread one =
                    new ConcurrentBorrowAndEvictThread(true);
            ConcurrentBorrowAndEvictThread two =
                    new ConcurrentBorrowAndEvictThread(false);

            one.start();
            two.start();
            one.join();
            two.join();

            pool.returnObject(one.obj);

            /* Uncomment this for a progress indication
            if (i % 10 == 0) {
                System.out.println(i/10);
            }
            */
        }
    }

    /**
     * POOL-189
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testWhenExhaustedBlockClosePool() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        Object obj1 = pool.borrowObject();

        // Make sure an object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);

        // close the pool (Bug POOL-189)
        pool.close();

        // Give interrupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);
    }

    private class ConcurrentBorrowAndEvictThread extends Thread {
        private boolean borrow;
        public String obj;

        public ConcurrentBorrowAndEvictThread(boolean borrow) {
            this.borrow = borrow;
        }

        @Override
        public void run() {
            try {
                if (borrow) {
                    obj = pool.borrowObject();
                } else {
                    pool.evict();
                }
            } catch (Exception e) { /* Ignore */}
        }
    }

    static class TestThread implements Runnable {
        private final java.util.Random _random = new java.util.Random();

        // Thread config items
        private final ObjectPool<String> _pool;
        private final int _iter;
        private final int _delay;
        private final boolean _randomDelay;
        private final Object _expectedObject;

        private volatile boolean _complete = false;
        private volatile boolean _failed = false;
        private volatile Throwable _error;

        public TestThread(ObjectPool<String> pool) {
            this(pool, 100, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter) {
            this(pool, iter, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay) {
            this(pool, iter, delay, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay) {
            this(pool, iter, delay, randomDelay, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay, Object obj) {
            _pool = pool;
            _iter = iter;
            _delay = delay;
            _randomDelay = randomDelay;
            _expectedObject = obj;
        }

        public boolean complete() {
            return _complete;
        }

        public boolean failed() {
            return _failed;
        }

        @Override
        public void run() {
            for(int i=0;i<_iter;i++) {
                long delay =
                    _randomDelay ? (long)_random.nextInt(_delay) : _delay;
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                String obj = null;
                try {
                    obj = _pool.borrowObject();
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }

                if (_expectedObject != null && !_expectedObject.equals(obj)) {
                    _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
                    _failed = true;
                    _complete = true;
                    break;
                }

                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                try {
                    _pool.returnObject(obj);
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }
            }
            _complete = true;
        }
    }

    @Test(timeout=60000)
    public void testFIFO() throws Exception {
        String o = null;
        pool.setLifo(false);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Oldest", "0", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Youngest", "2", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testLIFO() throws Exception {
        String o = null;
        pool.setLifo(true);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Youngest", "2", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Oldest", "0", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testAddObject() throws Exception {
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        pool.addObject();
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
        String obj = pool.borrowObject();
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        assertEquals("should be one active", 1, pool.getNumActive());
        pool.returnObject(obj);
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
    }

    protected GenericObjectPool<String> pool = null;

    private SimpleFactory factory = null;

    private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
        assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
                Boolean.valueOf(actual.getTestOnCreate()));
        assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
                Boolean.valueOf(actual.getTestOnBorrow()));
        assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
                Boolean.valueOf(actual.getTestOnReturn()));
        assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
                Boolean.valueOf(actual.getTestWhileIdle()));
        assertEquals("whenExhaustedAction",
                Boolean.valueOf(expected.getBlockWhenExhausted()),
                Boolean.valueOf(actual.getBlockWhenExhausted()));
        assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
        assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
        assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
        assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
        assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
        assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
    }

    public static class SimpleFactory implements PooledObjectFactory<String> {
        public SimpleFactory() {
            this(true);
        }
        public SimpleFactory(boolean valid) {
            this(valid,valid);
        }
        public SimpleFactory(boolean evalid, boolean ovalid) {
            evenValid = evalid;
            oddValid = ovalid;
        }
        public synchronized void setValid(boolean valid) {
            setEvenValid(valid);
            setOddValid(valid);
        }
        public synchronized void setEvenValid(boolean valid) {
            evenValid = valid;
        }
        public synchronized void setOddValid(boolean valid) {
            oddValid = valid;
        }
        public synchronized void setThrowExceptionOnPassivate(boolean bool) {
            exceptionOnPassivate = bool;
        }
        public synchronized void setMaxTotal(int maxTotal) {
            this.maxTotal = maxTotal;
        }
        public synchronized void setDestroyLatency(long destroyLatency) {
            this.destroyLatency = destroyLatency;
        }
        public synchronized void setMakeLatency(long makeLatency) {
            this.makeLatency = makeLatency;
        }
        public synchronized void setValidateLatency(long validateLatency) {
            this.validateLatency = validateLatency;
        }
        @Override
        public PooledObject<String> makeObject() {
            final long waitLatency;
            synchronized(this) {
                activeCount++;
                if (activeCount > maxTotal) {
                    throw new IllegalStateException(
                        "Too many active instances: " + activeCount);
                }
                waitLatency = makeLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            final int counter;
            synchronized(this) {
                counter = makeCounter++;
            }
            return new DefaultPooledObject<String>(String.valueOf(counter));
        }
        @Override
        public void destroyObject(PooledObject<String> obj) throws Exception {
            final long waitLatency;
            final boolean hurl;
            synchronized(this) {
                waitLatency = destroyLatency;
                hurl = exceptionOnDestroy;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            synchronized(this) {
                activeCount--;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        @Override
        public boolean validateObject(PooledObject<String> obj) {
            final boolean validate;
            final boolean evenTest;
            final boolean oddTest;
            final long waitLatency;
            final int counter;
            synchronized(this) {
                validate = enableValidation;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
                waitLatency = validateLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            if (validate) {
                return counter%2 == 0 ? evenTest : oddTest;
            }
            else {
                return true;
            }
        }
        @Override
        public void activateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            final boolean evenTest;
            final boolean oddTest;
            final int counter;
            synchronized(this) {
                hurl = exceptionOnActivate;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
            }
            if (hurl) {
                if (!(counter%2 == 0 ? evenTest : oddTest)) {
                    throw new Exception();
                }
            }
        }
        @Override
        public void passivateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            synchronized(this) {
                hurl = exceptionOnPassivate;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        int makeCounter = 0;
        int validateCounter = 0;
        int activeCount = 0;
        boolean evenValid = true;
        boolean oddValid = true;
        boolean exceptionOnPassivate = false;
        boolean exceptionOnActivate = false;
        boolean exceptionOnDestroy = false;
        boolean enableValidation = true;
        long destroyLatency = 0;
        long makeLatency = 0;
        long validateLatency = 0;
        int maxTotal = Integer.MAX_VALUE;

        public synchronized boolean isThrowExceptionOnActivate() {
            return exceptionOnActivate;
        }

        public synchronized void setThrowExceptionOnActivate(boolean b) {
            exceptionOnActivate = b;
        }

        public synchronized void setThrowExceptionOnDestroy(boolean b) {
            exceptionOnDestroy = b;
        }

        public synchronized boolean isValidationEnabled() {
            return enableValidation;
        }

        public synchronized void setValidationEnabled(boolean b) {
            enableValidation = b;
        }

        public synchronized int getMakeCounter() {
            return makeCounter;
        }

        private void doWait(long latency) {
            try {
                Thread.sleep(latency);
            } catch (InterruptedException ex) {
                // ignore
            }
        }
    }
    @Override
    protected boolean isLifo() {
        return true;
    }

    @Override
    protected boolean isFifo() {
        return false;
    }

    /*
     * Note: This test relies on timing for correct execution. There *should* be
     * enough margin for this to work correctly on most (all?) systems but be
     * aware of this if you see a failure of this test.
     */
    @Test(timeout=60000)
    public void testBorrowObjectFairness() {

        // Config
        int numThreads = 30;
        int maxTotal = 10;

        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
            Thread t = new Thread(threads[i]);
            t.start();
            // Short delay to ensure threads start in correct order
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                fail(e.toString());
            }
        }

        // Wait for threads to finish
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    /**
     * On first borrow, first object fails validation, second object is OK.
     * Subsequent borrows are OK. This was POOL-152.
     */
    @Test(timeout=60000)
    public void testBrokenFactoryShouldNotBlockPool() {
        int maxTotal = 1;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTestOnBorrow(true);

        // First borrow object will need to create a new object which will fail
        // validation.
        String obj = null;
        Exception ex = null;
        factory.setValid(false);
        try {
            obj = pool.borrowObject();
        } catch (Exception e) {
            ex = e;
        }
        // Failure expected
        assertNotNull(ex);
        assertTrue(ex instanceof NoSuchElementException);
        assertNull(obj);

        // Configure factory to create valid objects so subsequent borrows work
        factory.setValid(true);

        // Subsequent borrows should be OK
        try {
            obj = pool.borrowObject();
        } catch (Exception e1) {
            fail();
        }
        assertNotNull(obj);
        try {
            pool.returnObject(obj);
        } catch (Exception e) {
            fail();
        }
    }

    /*
     * Very simple test thread that just tries to borrow an object from
     * the provided pool returns it after a wait
     */
    static class WaitingTestThread extends Thread {
        private final GenericObjectPool<String> _pool;
        private final long _pause;
        private Throwable _thrown;

        private long preborrow; // just before borrow
        private long postborrow; //  borrow returned
        private long postreturn; // after object was returned
        private long ended;
        private String objectId;

        public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
            _pool = pool;
            _pause = pause;
            _thrown = null;
        }

        @Override
        public void run() {
            try {
                preborrow = System.currentTimeMillis();
                String obj = _pool.borrowObject();
                objectId = obj;
                postborrow = System.currentTimeMillis();
                Thread.sleep(_pause);
                _pool.returnObject(obj);
                postreturn = System.currentTimeMillis();
            } catch (Exception e) {
                _thrown = e;
            } finally{
                ended = System.currentTimeMillis();
            }
        }
    }

    private static final boolean DISPLAY_THREAD_DETAILS=
        Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
    // To pass this to a Maven test, use:
    // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
    // @see http://jira.codehaus.org/browse/SUREFIRE-121

    /*
     * Test multi-threaded pool access.
     * Multiple threads, but maxTotal only allows half the threads to succeed.
     *
     * This test was prompted by Continuum build failures in the Commons DBCP test case:
     * TestPerUserPoolDataSource.testMultipleThreads2()
     * Let's see if the this fails on Continuum too!
     */
    @Test(timeout=60000)
    public void testMaxWaitMultiThreaded() throws Exception {
        final long maxWait = 500; // wait for connection
        final long holdTime = 2 * maxWait; // how long to hold connection
        final int threads = 10; // number of threads to grab the object initially
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(maxWait);
        pool.setMaxTotal(threads);
        // Create enough threads so half the threads will have to wait
        WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
        for(int i=0; i < wtt.length; i++){
            wtt[i] = new WaitingTestThread(pool,holdTime);
        }
        long origin = System.currentTimeMillis()-1000;
        for(int i=0; i < wtt.length; i++){
            wtt[i].start();
        }
        int failed = 0;
        for(int i=0; i < wtt.length; i++){
            wtt[i].join();
            if (wtt[i]._thrown != null){
                failed++;
            }
        }
        if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
            System.out.println(
                    "MaxWait: " + maxWait +
                    " HoldTime: " + holdTime +
                     " MaxTotal: " + threads +
                    " Threads: " + wtt.length +
                    " Failed: " + failed
                    );
            for(int i=0; i < wtt.length; i++){
                WaitingTestThread wt = wtt[i];
                System.out.println(
                        "Preborrow: " + (wt.preborrow-origin) +
                        " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
                        " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
                        " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
                        " Ended: " + (wt.ended-origin) +
                        " ObjId: " + wt.objectId
                        );
            }
        }
        assertEquals("Expected half the threads to fail",wtt.length/2,failed);
    }

    /**
     * Test the following scenario:
     *   Thread 1 borrows an instance
     *   Thread 2 starts to borrow another instance before thread 1 returns its instance
     *   Thread 1 returns its instance while thread 2 is validating its newly created instance
     * The test verifies that the instance created by Thread 2 is not leaked.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMakeConcurrentWithReturn() throws Exception {
        pool.setTestOnBorrow(true);
        factory.setValid(true);
        // Borrow and return an instance, with a short wait
        WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
        thread1.start();
        Thread.sleep(50); // wait for validation to succeed
        // Slow down validation and borrow an instance
        factory.setValidateLatency(400);
        String instance = pool.borrowObject();
        // Now make sure that we have not leaked an instance
        assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
        pool.returnObject(instance);
        assertEquals(factory.getMakeCounter(), pool.getNumIdle());
    }

    /**
     * Ensure the pool is registered.
     */
    @Test(timeout=60000)
    public void testJmxRegistration() {
        ObjectName oname = pool.getJmxName();
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(oname, null);
        Assert.assertEquals(1, result.size());
        pool.jmxUnregister();

        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setJmxEnabled(false);
        GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
        assertNull(poolWithoutJmx.getJmxName());
        config.setJmxEnabled(true);
        poolWithoutJmx.jmxUnregister();

        config.setJmxNameBase(null);
        GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
        assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a checked out object is
     * invalidated.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testInvalidateFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(500);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance
        String obj = pool.borrowObject();
        // Launch another thread - will block, but fail in 500 ms
        WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
        thread2.start();
        // Invalidate the object borrowed by this thread - should allow thread2 to create
        Thread.sleep(20);
        pool.invalidateObject(obj);
        Thread.sleep(600); // Wait for thread2 to timeout
        if (thread2._thrown != null) {
            fail(thread2._thrown.toString());
        }
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a returning object fails
     * validation.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testValidationFailureOnReturnFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        factory.setValid(false); // Validate will always fail
        factory.setValidationEnabled(true);
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(1500);
        pool.setTestOnReturn(true);
        pool.setTestOnBorrow(false);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance and return it after 500 ms (validation will fail)
        WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
        thread2.start();
        Thread.sleep(50);
        // Try to borrow an object
        String obj = pool.borrowObject();
        pool.returnObject(obj);
    }

    @Test
    public void testSwallowedExceptionListener() {
        pool.setSwallowedExceptionListener(null); // must simply return
        final List<Exception> swallowedExceptions = new ArrayList<Exception>();
        /*
         * A simple listener, that will throw a OOM on 3rd exception.
         */
        final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
            @Override
            public void onSwallowException(Exception e) {
                if (swallowedExceptions.size() == 2) {
                    throw new OutOfMemoryError();
                } else {
                    swallowedExceptions.add(e);
                }
            }
        };
        pool.setSwallowedExceptionListener(listener);

        Exception e1 = new Exception();
        Exception e2 = new ArrayIndexOutOfBoundsException();

        pool.swallowException(e1);
        pool.swallowException(e2);

        try {
            pool.swallowException(e1);
            fail("Not supposed to get here");
        } catch (OutOfMemoryError oom) {
            // expected
        }

        assertEquals(2, swallowedExceptions.size());
    }

    // POOL-248
    @Test(expected=IllegalStateException.class)
    public void testMultipleReturnOfSameObject() throws Exception {
        final GenericObjectPool<String> pool = new GenericObjectPool<String>(
                factory, new GenericObjectPoolConfig());

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        String obj = pool.borrowObject();

        Assert.assertEquals(1, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());
    }

    private static final class DummyFactory
            extends BasePooledObjectFactory<Object> {
        @Override
        public Object create() throws Exception {
            return null;
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }
    }


    private static class InvalidFactory
            extends BasePooledObjectFactory<Object> {

        @Override
        public Object create() throws Exception {
            return new Object();
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }

        @Override
        public boolean validateObject(PooledObject<Object> obj) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // Ignore
            }
            return false;
        }
    }

    private static class EvictionThread<T> extends Thread {

        private final GenericObjectPool<T> pool;

        public EvictionThread(GenericObjectPool<T> pool) {
            this.pool = pool;
        }

        @Override
        public void run() {
            try {
                pool.evict();
            } catch (Exception e) {
                // Ignore
            }
        }
    }
}
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.pool2.impl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.SwallowedExceptionListener;
import org.apache.commons.pool2.TestBaseObjectPool;
import org.apache.commons.pool2.VisitTracker;
import org.apache.commons.pool2.VisitTrackerFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @version $Revision: 1569016 $
 */
public class TestGenericObjectPool extends TestBaseObjectPool {

    @Override
    protected ObjectPool<String> makeEmptyPool(int mincap) {
       GenericObjectPool<String> mtPool =
               new GenericObjectPool<String>(new SimpleFactory());
       mtPool.setMaxTotal(mincap);
       mtPool.setMaxIdle(mincap);
       return mtPool;
    }

    @Override
    protected ObjectPool<Object> makeEmptyPool(
            final PooledObjectFactory<Object> fac) {
        return new GenericObjectPool<Object>(fac);
    }

    @Override
    protected Object getNthObject(int n) {
        return String.valueOf(n);
    }

    @Before
    public void setUp() throws Exception {
        factory = new SimpleFactory();
        pool = new GenericObjectPool<String>(factory);
    }

    @After
    public void tearDown() throws Exception {
        String poolName = pool.getJmxName().toString();
        pool.clear();
        pool.close();
        pool = null;
        factory = null;

        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(new ObjectName(
                "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
        // There should be no registered pools at this point
        int registeredPoolCount = result.size();
        StringBuilder msg = new StringBuilder("Current pool is: ");
        msg.append(poolName);
        msg.append("  Still open pools are: ");
        for (ObjectName name : result) {
            // Clean these up ready for the next test
            msg.append(name.toString());
            msg.append(" created via\n");
            msg.append(mbs.getAttribute(name, "CreationStackTrace"));
            msg.append('\n');
            mbs.unregisterMBean(name);
        }
        Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
    }

    @Test(expected=IllegalArgumentException.class)
    public void testConstructorNullFactory() {
        // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
        assertNotNull(new GenericObjectPool<String>(null));
        // TODO this currently causes tearDown to report an error
        // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
    }

    @Test(timeout=60000)
    public void testConstructors() throws Exception {

        // Make constructor arguments all different from defaults
        int minIdle = 2;
        long maxWait = 3;
        int maxIdle = 4;
        int maxTotal = 5;
        long minEvictableIdleTimeMillis = 6;
        int numTestsPerEvictionRun = 7;
        boolean testOnBorrow = true;
        boolean testOnReturn = true;
        boolean testWhileIdle = true;
        long timeBetweenEvictionRunsMillis = 8;
        boolean blockWhenExhausted = false;
        boolean lifo = false;
        PooledObjectFactory<Object> dummyFactory = new DummyFactory();
        GenericObjectPool<Object> dummyPool =
                new GenericObjectPool<Object>(dummyFactory);
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
                Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();

        GenericObjectPoolConfig config =
                new GenericObjectPoolConfig();
        config.setLifo(lifo);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWait);
        config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setTestWhileIdle(testWhileIdle);
        config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        config.setBlockWhenExhausted(blockWhenExhausted);
        dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
        assertEquals(maxIdle, dummyPool.getMaxIdle());
        assertEquals(maxWait, dummyPool.getMaxWaitMillis());
        assertEquals(minIdle, dummyPool.getMinIdle());
        assertEquals(maxTotal, dummyPool.getMaxTotal());
        assertEquals(minEvictableIdleTimeMillis,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(testOnBorrow),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(testOnReturn),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(testWhileIdle),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(timeBetweenEvictionRunsMillis,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(blockWhenExhausted),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedFail() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(false);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumIdle());
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlock() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(10L);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlockInterupt() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        String obj1 = pool.borrowObject();

        // Make sure on object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);
        wtt.interrupt();

        // Give interupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);

        // Return object to the pool
        pool.returnObject(obj1);

        // Bug POOL-162 - check there is now an object in the pool
        pool.setMaxWaitMillis(10L);
        String obj2 = null;
        try {
             obj2 = pool.borrowObject();
            assertNotNull(obj2);
        } catch(NoSuchElementException e) {
            // Not expected
            fail("NoSuchElementException not expected");
        }
        pool.returnObject(obj2);
        pool.close();

    }

    @Test(timeout=60000)
    public void testEvictWhileEmpty() throws Exception {
        pool.evict();
        pool.evict();
        pool.close();
    }

    /**
     * Tests addObject contention between ensureMinIdle triggered by
     * the Evictor with minIdle &gt; 0 and borrowObject.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictAddObjects() throws Exception {
        factory.setMakeLatency(300);
        factory.setMaxTotal(2);
        pool.setMaxTotal(2);
        pool.setMinIdle(1);
        pool.borrowObject(); // numActive = 1, numIdle = 0
        // Create a test thread that will run once and try a borrow after
        // 150ms fixed delay
        TestThread borrower = new TestThread(pool, 1, 150, false);
        Thread borrowerThread = new Thread(borrower);
        // Set evictor to run in 100 ms - will create idle instance
        pool.setTimeBetweenEvictionRunsMillis(100);
        borrowerThread.start();  // Off to the races
        borrowerThread.join();
        assertTrue(!borrower.failed());
    }

    @Test(timeout=60000)
    public void testEvictLIFO() throws Exception {
        checkEvict(true);
    }

    @Test(timeout=60000)
    public void testEvictFIFO() throws Exception {
        checkEvict(false);
    }

    private void checkEvict(boolean lifo) throws Exception {
        // yea this is hairy but it tests all the code paths in GOP.evict()
        pool.setSoftMinEvictableIdleTimeMillis(10);
        pool.setMinIdle(2);
        pool.setTestWhileIdle(true);
        pool.setLifo(lifo);
        PoolUtils.prefill(pool, 5);
        pool.evict();
        factory.setEvenValid(false);
        factory.setOddValid(false);
        factory.setThrowExceptionOnActivate(true);
        pool.evict();
        PoolUtils.prefill(pool, 5);
        factory.setThrowExceptionOnActivate(false);
        factory.setThrowExceptionOnPassivate(true);
        pool.evict();
        factory.setThrowExceptionOnPassivate(false);
        factory.setEvenValid(true);
        factory.setOddValid(true);
        Thread.sleep(125);
        pool.evict();
        assertEquals(2, pool.getNumIdle());
    }

    /**
     * Test to make sure evictor visits least recently used objects first,
     * regardless of FIFO/LIFO.
     *
     * JIRA: POOL-86
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictionOrder() throws Exception {
        checkEvictionOrder(false);
        tearDown();
        setUp();
        checkEvictionOrder(true);
    }

    private void checkEvictionOrder(boolean lifo) throws Exception {
        checkEvictionOrderPart1(lifo);
        tearDown();
        setUp();
        checkEvictionOrderPart2(lifo);
    }

    private void checkEvictionOrderPart1(boolean lifo) throws Exception {
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        // Order, oldest to youngest, is "0", "1", ...,"4"
        pool.evict(); // Should evict "0" and "1"
        Object obj = pool.borrowObject();
        assertTrue("oldest not evicted", !obj.equals("0"));
        assertTrue("second oldest not evicted", !obj.equals("1"));
        // 2 should be next out for FIFO, 4 for LIFO
        assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
    }

    private void checkEvictionOrderPart2(boolean lifo) throws Exception {
        // Two eviction runs in sequence
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        pool.evict(); // Should evict "0" and "1"
        pool.evict(); // Should evict "2" and "3"
        Object obj = pool.borrowObject();
        assertEquals("Wrong instance remaining in pool", "4", obj);
    }

    /**
     * Verifies that the evictor visits objects in expected order
     * and frequency.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testEvictorVisiting() throws Exception {
        checkEvictorVisiting(true);
        checkEvictorVisiting(false);
    }

    private void checkEvictorVisiting(boolean lifo) throws Exception {
        VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
        GenericObjectPool<VisitTracker<Object>> trackerPool =
                new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(2);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // Visit oldest 2 - 0 and 1
        VisitTracker<Object> obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        //  borrow, return, borrow, return
        //  FIFO will move 0 and 1 to end
        //  LIFO, 7 out, then in, then out, then in
        trackerPool.evict();  // Should visit 2 and 3 in either case
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() >= 4) {
                assertEquals("Unexpected instance visited " + tracker.getId(),
                        0, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        trackerFactory = new VisitTrackerFactory<Object>();
        trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(3);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // 0, 1, 2
        trackerPool.evict(); // 3, 4, 5
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        // borrow, return, borrow, return
        //  FIFO 3,4,5,6,7,0,1,2
        //  LIFO 7,6,5,4,3,2,1,0
        // In either case, pointer should be at 6
        trackerPool.evict();
        // Should hit 6,7,0 - 0 for second time
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() != 0) {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        2, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        // Randomly generate a pools with random numTests
        // and make sure evictor cycles through elements appropriately
        int[] smallPrimes = {2, 3, 5, 7};
        Random random = new Random();
        random.setSeed(System.currentTimeMillis());
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 5; j++) {
                trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
                trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
                trackerPool.setMinEvictableIdleTimeMillis(-1);
                trackerPool.setTestWhileIdle(true);
                trackerPool.setLifo(lifo);
                trackerPool.setTestOnReturn(false);
                trackerPool.setTestOnBorrow(false);
                trackerPool.setMaxIdle(-1);
                int instanceCount = 10 + random.nextInt(20);
                trackerPool.setMaxTotal(instanceCount);
                for (int k = 0; k < instanceCount; k++) {
                    trackerPool.addObject();
                }

                // Execute a random number of evictor runs
                int runs = 10 + random.nextInt(50);
                for (int k = 0; k < runs; k++) {
                    trackerPool.evict();
                }

                // Number of times evictor should have cycled through the pool
                int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
                        instanceCount;

                // Look at elements and make sure they are visited cycleCount
                // or cycleCount + 1 times
                VisitTracker<Object> tracker = null;
                int visitCount = 0;
                for (int k = 0; k < instanceCount; k++) {
                    tracker = trackerPool.borrowObject();
                    assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
                    visitCount = tracker.getValidateCount();
                    assertTrue(visitCount >= cycleCount &&
                            visitCount <= cycleCount + 1);
                }
                trackerPool.close();
            }
        }
    }

    @Test(timeout=60000)
    public void testExceptionOnPassivateDuringReturn() throws Exception {
        String obj = pool.borrowObject();
        factory.setThrowExceptionOnPassivate(true);
        pool.returnObject(obj);
        assertEquals(0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringBorrow() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnBorrow(true);
        pool.borrowObject();
        factory.setValid(false); // Make validation fail on next borrow attempt
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringReturn() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnReturn(true);
        String obj1 = pool.borrowObject();
        pool.borrowObject();
        factory.setValid(false); // Make validation fail
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnActivateDuringBorrow() throws Exception {
        String obj1 = pool.borrowObject();
        String obj2 = pool.borrowObject();
        pool.returnObject(obj1);
        pool.returnObject(obj2);
        factory.setThrowExceptionOnActivate(true);
        factory.setEvenValid(false);
        // Activation will now throw every other time
        // First attempt throws, but loop continues and second succeeds
        String obj = pool.borrowObject();
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);
        factory.setValid(false);
        // Validation will now fail on activation when borrowObject returns
        // an idle instance, and then when attempting to create a new instance
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(0, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testNegativeMaxTotal() throws Exception {
        pool.setMaxTotal(-1);
        pool.setBlockWhenExhausted(false);
        String obj = pool.borrowObject();
        assertEquals(getNthObject(0),obj);
        pool.returnObject(obj);
    }

    @Test(timeout=60000)
    public void testMaxIdle() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(8);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxIdleZero() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(0);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals(0, pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxTotal() throws Exception {
        pool.setMaxTotal(3);
        pool.setBlockWhenExhausted(false);

        pool.borrowObject();
        pool.borrowObject();
        pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testTimeoutNoLeak() throws Exception {
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(10);
        pool.setBlockWhenExhausted(true);
        String obj = pool.borrowObject();
        String obj2 = pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        pool.returnObject(obj2);
        pool.returnObject(obj);

        pool.borrowObject();
        pool.borrowObject();
    }

    @Test(timeout=60000)
    public void testMaxTotalZero() throws Exception {
        pool.setMaxTotal(0);
        pool.setBlockWhenExhausted(false);

        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testMaxTotalUnderLoad() {
        // Config
        int numThreads = 199; // And main thread makes a round 200.
        int numIter = 20;
        int delay = 25;
        int maxTotal = 10;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            // Factor of 2 on iterations so main thread does work whilst other
            // threads are running. Factor of 2 on delay so average delay for
            // other threads == actual delay for main thread
            threads[i] = new TestThread(pool, numIter * 2, delay * 2);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        // Give the threads a chance to start doing some work
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) {
            // ignored
        }

        for (int i = 0; i < numIter; i++) {
            String obj = null;
            try {
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                obj = pool.borrowObject();
                // Under load, observed _numActive > _maxTotal
                if (pool.getNumActive() > pool.getMaxTotal()) {
                    throw new IllegalStateException("Too many active objects");
                }
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
            } catch (Exception e) {
                // Shouldn't happen
                e.printStackTrace();
                fail("Exception on borrow");
            } finally {
                if (obj != null) {
                    try {
                        pool.returnObject(obj);
                    } catch (Exception e) {
                        // Ignore
                    }
                }
            }
        }

        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testSettersAndGetters() throws Exception {
        {
            // The object receives an Exception during its creation to prevent
            // memory leaks. See BaseGenericObjectPool constructor for more details.
            assertTrue(false == "".equals(pool.getCreationStackTrace()));
        }
        {
            assertEquals(0, pool.getBorrowedCount());
        }
        {
            assertEquals(0, pool.getReturnedCount());
        }
        {
            assertEquals(0, pool.getCreatedCount());
        }
        {
            assertEquals(0, pool.getDestroyedCount());
        }
        {
            assertEquals(0, pool.getDestroyedByEvictorCount());
        }
        {
            assertEquals(0, pool.getDestroyedByBorrowValidationCount());
        }
        {
            assertEquals(0, pool.getMeanActiveTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanIdleTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getNumIdle());
        }
        {
            pool.setMaxTotal(123);
            assertEquals(123,pool.getMaxTotal());
        }
        {
            pool.setMaxIdle(12);
            assertEquals(12,pool.getMaxIdle());
        }
        {
            pool.setMaxWaitMillis(1234L);
            assertEquals(1234L,pool.getMaxWaitMillis());
        }
        {
            pool.setMinEvictableIdleTimeMillis(12345L);
            assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
        }
        {
            pool.setNumTestsPerEvictionRun(11);
            assertEquals(11,pool.getNumTestsPerEvictionRun());
        }
        {
            pool.setTestOnBorrow(true);
            assertTrue(pool.getTestOnBorrow());
            pool.setTestOnBorrow(false);
            assertTrue(!pool.getTestOnBorrow());
        }
        {
            pool.setTestOnReturn(true);
            assertTrue(pool.getTestOnReturn());
            pool.setTestOnReturn(false);
            assertTrue(!pool.getTestOnReturn());
        }
        {
            pool.setTestWhileIdle(true);
            assertTrue(pool.getTestWhileIdle());
            pool.setTestWhileIdle(false);
            assertTrue(!pool.getTestWhileIdle());
        }
        {
            pool.setTimeBetweenEvictionRunsMillis(11235L);
            assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
        }
        {
            pool.setSoftMinEvictableIdleTimeMillis(12135L);
            assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
        }
        {
            pool.setBlockWhenExhausted(true);
            assertTrue(pool.getBlockWhenExhausted());
            pool.setBlockWhenExhausted(false);
            assertFalse(pool.getBlockWhenExhausted());
        }
    }

    @Test(timeout=60000)
    public void testDefaultConfiguration() throws Exception {
        assertConfiguration(new GenericObjectPoolConfig(),pool);
    }

    @Test(timeout=60000)
    public void testSetConfig() throws Exception {
        GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
        assertConfiguration(expected,pool);
        expected.setMaxTotal(2);
        expected.setMaxIdle(3);
        expected.setMaxWaitMillis(5L);
        expected.setMinEvictableIdleTimeMillis(7L);
        expected.setNumTestsPerEvictionRun(9);
        expected.setTestOnCreate(true);
        expected.setTestOnBorrow(true);
        expected.setTestOnReturn(true);
        expected.setTestWhileIdle(true);
        expected.setTimeBetweenEvictionRunsMillis(11L);
        expected.setBlockWhenExhausted(false);
        pool.setConfig(expected);
        assertConfiguration(expected,pool);
    }

    @Test(timeout=60000)
    public void testStartAndStopEvictor() throws Exception {
        // set up pool without evictor
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(6);
        pool.setMinEvictableIdleTimeMillis(100L);

        for(int j=0;j<2;j++) {
            // populate the pool
            {
                String[] active = new String[6];
                for(int i=0;i<6;i++) {
                    active[i] = pool.borrowObject();
                }
                for(int i=0;i<6;i++) {
                    pool.returnObject(active[i]);
                }
            }

            // note that it stays populated
            assertEquals("Should have 6 idle",6,pool.getNumIdle());

            // start the evictor
            pool.setTimeBetweenEvictionRunsMillis(50L);

            // wait a second (well, .2 seconds)
            try { Thread.sleep(200L); } catch(InterruptedException e) { }

            // assert that the evictor has cleared out the pool
            assertEquals("Should have 0 idle",0,pool.getNumIdle());

            // stop the evictor
            pool.startEvictor(0L);
        }
    }

    @Test(timeout=60000)
    public void testEvictionWithNegativeNumTests() throws Exception {
        // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(-2);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);

        String[] active = new String[6];
        for(int i=0;i<6;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<6;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testEviction() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(100);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());

        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {

        private AtomicInteger callCount = new AtomicInteger(0);

        @Override
        public boolean evict(EvictionConfig config, PooledObject<T> underTest,
                int idleCount) {
            if (callCount.incrementAndGet() > 1500) {
                return true;
            } else {
                return false;
            }
        }
    }

    @Test(timeout=60000)
    public void testEvictionPolicy() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(500);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        // ClassNotFoundException
        try {
            pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // InstantiationException
        try {
            pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // IllegalAccessException
        try {
            pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
        assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        // Eviction policy ignores first 1500 attempts to evict and then always
        // evicts. After 1s, there should have been two runs of 500 tests so no
        // evictions
        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertEquals("Should be 500 idle", 500, pool.getNumIdle());
        // A further 1s wasn't enough so allow 2s for the evictor to clear out
        // all of the idle objects.
        try { Thread.sleep(2000L); } catch(InterruptedException e) { }
        assertEquals("Should be 0 idle", 0, pool.getNumIdle());
    }


    @Test(timeout=60000)
    public void testEvictionSoftMinIdle() throws Exception {
        class TimeTest extends BasePooledObjectFactory<TimeTest> {
            private final long createTime;
            public TimeTest() {
                createTime = System.currentTimeMillis();
            }
            @Override
            public TimeTest create() throws Exception {
                return new TimeTest();
            }
            @Override
            public PooledObject<TimeTest> wrap(TimeTest value) {
                return new DefaultPooledObject<TimeTest>(value);
            }
            public long getCreateTime() {
                return createTime;
            }
        }

        GenericObjectPool<TimeTest> timePool =
            new GenericObjectPool<TimeTest>(new TimeTest());

        timePool.setMaxIdle(5);
        timePool.setMaxTotal(5);
        timePool.setNumTestsPerEvictionRun(5);
        timePool.setMinEvictableIdleTimeMillis(3000L);
        timePool.setSoftMinEvictableIdleTimeMillis(1000L);
        timePool.setMinIdle(2);

        TimeTest[] active = new TimeTest[5];
        Long[] creationTime = new Long[5] ;
        for(int i=0;i<5;i++) {
            active[i] = timePool.borrowObject();
            creationTime[i] = Long.valueOf((active[i]).getCreateTime());
        }

        for(int i=0;i<5;i++) {
            timePool.returnObject(active[i]);
        }

        // Soft evict all but minIdle(2)
        Thread.sleep(1500L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());

        // Hard evict the rest.
        Thread.sleep(2000L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
        timePool.close();
    }

    @Test(timeout=60000)
    public void testEvictionInvalid() throws Exception {

        final GenericObjectPool<Object> invalidFactoryPool =
                new GenericObjectPool<Object>(new InvalidFactory());

        invalidFactoryPool.setMaxIdle(1);
        invalidFactoryPool.setMaxTotal(1);
        invalidFactoryPool.setTestOnBorrow(false);
        invalidFactoryPool.setTestOnReturn(false);
        invalidFactoryPool.setTestWhileIdle(true);
        invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
        invalidFactoryPool.setNumTestsPerEvictionRun(1);

        Object p = invalidFactoryPool.borrowObject();
        invalidFactoryPool.returnObject(p);

        // Run eviction in a separate thread
        Thread t = new EvictionThread<Object>(invalidFactoryPool);
        t.start();

        // Sleep to make sure evictor has started
        Thread.sleep(300);

        try {
            invalidFactoryPool.borrowObject(1);
        } catch (NoSuchElementException nsee) {
            // Ignore
        }

        // Make sure evictor has finished
        Thread.sleep(1000);

        // Should have an empty pool
        assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
        assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
        invalidFactoryPool.close();
    }

    /**
     * POOL-231 - verify that concurrent invalidates of the same object do not
     * corrupt pool destroyCount.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testConcurrentInvalidate() throws Exception {
        // Get allObjects and idleObjects loaded with some instances
        final int nObjects = 1000;
        pool.setMaxTotal(nObjects);
        pool.setMaxIdle(nObjects);
        final String[] obj = new String[nObjects];
        for (int i = 0; i < nObjects; i++) {
            obj[i] = pool.borrowObject();
        }
        for (int i = 0; i < nObjects; i++) {
            if (i % 2 == 0) {
                pool.returnObject(obj[i]);
            }
        }
        final int nThreads = 20;
        final int nIterations = 60;
        final InvalidateThread[] threads = new InvalidateThread[nThreads];
        // Randomly generated list of distinct invalidation targets
        final ArrayList<Integer> targets = new ArrayList<Integer>();
        final Random random = new Random();
        for (int j = 0; j < nIterations; j++) {
            // Get a random invalidation target
            Integer targ = Integer.valueOf(random.nextInt(nObjects));
            while (targets.contains(targ)) {
                targ = Integer.valueOf(random.nextInt(nObjects));
            }
            targets.add(targ);
            // Launch nThreads threads all trying to invalidate the target
            for (int i = 0; i < nThreads; i++) {
                threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
            }
            for (int i = 0; i < nThreads; i++) {
                new Thread(threads[i]).start();
            }
            boolean done = false;
            while (!done) {
                done = true;
                for (int i = 0; i < nThreads; i++) {
                    done = done && threads[i].complete();
                }
                Thread.sleep(100);
            }
        }
        Assert.assertEquals(nIterations, pool.getDestroyedCount());
    }

    /**
     * Attempts to invalidate an object, swallowing IllegalStateException.
     */
    static class InvalidateThread implements Runnable {
        private final String obj;
        private final ObjectPool<String> pool;
        private boolean done = false;
        public InvalidateThread(ObjectPool<String> pool, String obj) {
            this.obj = obj;
            this.pool = pool;
        }
        @Override
        public void run() {
            try {
                pool.invalidateObject(obj);
            } catch (IllegalStateException ex) {
                // Ignore
            } catch (Exception ex) {
                Assert.fail("Unexpected exception " + ex.toString());
            } finally {
                done = true;
            }
        }
        public boolean complete() {
            return done;
        }
    }

    @Test(timeout=60000)
    public void testMinIdle() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[5];
        active[0] = pool.borrowObject();

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=1 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    @Test(timeout=60000)
    public void testMinIdleMaxTotal() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[10];

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);

        for(int i=0 ; i<10 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);

        for(int i=0 ; i<10 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    /**
     * Kicks off <numThreads> test threads, each of which will go through
     * <iterations> borrow-return cycles with random delay times <= delay
     * in between.
     */
    private void runTestThreads(int numThreads, int iterations, int delay) {
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool,iterations,delay);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testThreaded1() throws Exception {
        pool.setMaxTotal(15);
        pool.setMaxIdle(15);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(20, 100, 50);
    }

    /**
     * Verifies that maxTotal is not exceeded when factory destroyObject
     * has high latency, testOnReturn is set and there is high incidence of
     * validation failures.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMaxTotalInvariant() throws Exception {
        int maxTotal = 15;
        factory.setEvenValid(false);     // Every other validation fails
        factory.setDestroyLatency(100);  // Destroy takes 100 ms
        factory.setMaxTotal(maxTotal); // (makes - destroys) bound
        factory.setValidationEnabled(true);
        pool.setMaxTotal(maxTotal);
        pool.setMaxIdle(-1);
        pool.setTestOnReturn(true);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(5, 10, 50);
    }

    @Test(timeout=60000)
    public void testConcurrentBorrowAndEvict() throws Exception {

        pool.setMaxTotal(1);
        pool.addObject();

        for( int i=0; i<5000; i++) {
            ConcurrentBorrowAndEvictThread one =
                    new ConcurrentBorrowAndEvictThread(true);
            ConcurrentBorrowAndEvictThread two =
                    new ConcurrentBorrowAndEvictThread(false);

            one.start();
            two.start();
            one.join();
            two.join();

            pool.returnObject(one.obj);

            /* Uncomment this for a progress indication
            if (i % 10 == 0) {
                System.out.println(i/10);
            }
            */
        }
    }

    /**
     * POOL-189
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testWhenExhaustedBlockClosePool() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        Object obj1 = pool.borrowObject();

        // Make sure an object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);

        // close the pool (Bug POOL-189)
        pool.close();

        // Give interrupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);
    }

    private class ConcurrentBorrowAndEvictThread extends Thread {
        private boolean borrow;
        public String obj;

        public ConcurrentBorrowAndEvictThread(boolean borrow) {
            this.borrow = borrow;
        }

        @Override
        public void run() {
            try {
                if (borrow) {
                    obj = pool.borrowObject();
                } else {
                    pool.evict();
                }
            } catch (Exception e) { /* Ignore */}
        }
    }

    static class TestThread implements Runnable {
        private final java.util.Random _random = new java.util.Random();

        // Thread config items
        private final ObjectPool<String> _pool;
        private final int _iter;
        private final int _delay;
        private final boolean _randomDelay;
        private final Object _expectedObject;

        private volatile boolean _complete = false;
        private volatile boolean _failed = false;
        private volatile Throwable _error;

        public TestThread(ObjectPool<String> pool) {
            this(pool, 100, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter) {
            this(pool, iter, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay) {
            this(pool, iter, delay, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay) {
            this(pool, iter, delay, randomDelay, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay, Object obj) {
            _pool = pool;
            _iter = iter;
            _delay = delay;
            _randomDelay = randomDelay;
            _expectedObject = obj;
        }

        public boolean complete() {
            return _complete;
        }

        public boolean failed() {
            return _failed;
        }

        @Override
        public void run() {
            for(int i=0;i<_iter;i++) {
                long delay =
                    _randomDelay ? (long)_random.nextInt(_delay) : _delay;
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                String obj = null;
                try {
                    obj = _pool.borrowObject();
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }

                if (_expectedObject != null && !_expectedObject.equals(obj)) {
                    _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
                    _failed = true;
                    _complete = true;
                    break;
                }

                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                try {
                    _pool.returnObject(obj);
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }
            }
            _complete = true;
        }
    }

    @Test(timeout=60000)
    public void testFIFO() throws Exception {
        String o = null;
        pool.setLifo(false);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Oldest", "0", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Youngest", "2", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testLIFO() throws Exception {
        String o = null;
        pool.setLifo(true);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Youngest", "2", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Oldest", "0", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testAddObject() throws Exception {
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        pool.addObject();
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
        String obj = pool.borrowObject();
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        assertEquals("should be one active", 1, pool.getNumActive());
        pool.returnObject(obj);
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
    }

    protected GenericObjectPool<String> pool = null;

    private SimpleFactory factory = null;

    private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
        assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
                Boolean.valueOf(actual.getTestOnCreate()));
        assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
                Boolean.valueOf(actual.getTestOnBorrow()));
        assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
                Boolean.valueOf(actual.getTestOnReturn()));
        assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
                Boolean.valueOf(actual.getTestWhileIdle()));
        assertEquals("whenExhaustedAction",
                Boolean.valueOf(expected.getBlockWhenExhausted()),
                Boolean.valueOf(actual.getBlockWhenExhausted()));
        assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
        assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
        assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
        assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
        assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
        assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
    }

    public static class SimpleFactory implements PooledObjectFactory<String> {
        public SimpleFactory() {
            this(true);
        }
        public SimpleFactory(boolean valid) {
            this(valid,valid);
        }
        public SimpleFactory(boolean evalid, boolean ovalid) {
            evenValid = evalid;
            oddValid = ovalid;
        }
        public synchronized void setValid(boolean valid) {
            setEvenValid(valid);
            setOddValid(valid);
        }
        public synchronized void setEvenValid(boolean valid) {
            evenValid = valid;
        }
        public synchronized void setOddValid(boolean valid) {
            oddValid = valid;
        }
        public synchronized void setThrowExceptionOnPassivate(boolean bool) {
            exceptionOnPassivate = bool;
        }
        public synchronized void setMaxTotal(int maxTotal) {
            this.maxTotal = maxTotal;
        }
        public synchronized void setDestroyLatency(long destroyLatency) {
            this.destroyLatency = destroyLatency;
        }
        public synchronized void setMakeLatency(long makeLatency) {
            this.makeLatency = makeLatency;
        }
        public synchronized void setValidateLatency(long validateLatency) {
            this.validateLatency = validateLatency;
        }
        @Override
        public PooledObject<String> makeObject() {
            final long waitLatency;
            synchronized(this) {
                activeCount++;
                if (activeCount > maxTotal) {
                    throw new IllegalStateException(
                        "Too many active instances: " + activeCount);
                }
                waitLatency = makeLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            final int counter;
            synchronized(this) {
                counter = makeCounter++;
            }
            return new DefaultPooledObject<String>(String.valueOf(counter));
        }
        @Override
        public void destroyObject(PooledObject<String> obj) throws Exception {
            final long waitLatency;
            final boolean hurl;
            synchronized(this) {
                waitLatency = destroyLatency;
                hurl = exceptionOnDestroy;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            synchronized(this) {
                activeCount--;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        @Override
        public boolean validateObject(PooledObject<String> obj) {
            final boolean validate;
            final boolean evenTest;
            final boolean oddTest;
            final long waitLatency;
            final int counter;
            synchronized(this) {
                validate = enableValidation;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
                waitLatency = validateLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            if (validate) {
                return counter%2 == 0 ? evenTest : oddTest;
            }
            else {
                return true;
            }
        }
        @Override
        public void activateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            final boolean evenTest;
            final boolean oddTest;
            final int counter;
            synchronized(this) {
                hurl = exceptionOnActivate;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
            }
            if (hurl) {
                if (!(counter%2 == 0 ? evenTest : oddTest)) {
                    throw new Exception();
                }
            }
        }
        @Override
        public void passivateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            synchronized(this) {
                hurl = exceptionOnPassivate;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        int makeCounter = 0;
        int validateCounter = 0;
        int activeCount = 0;
        boolean evenValid = true;
        boolean oddValid = true;
        boolean exceptionOnPassivate = false;
        boolean exceptionOnActivate = false;
        boolean exceptionOnDestroy = false;
        boolean enableValidation = true;
        long destroyLatency = 0;
        long makeLatency = 0;
        long validateLatency = 0;
        int maxTotal = Integer.MAX_VALUE;

        public synchronized boolean isThrowExceptionOnActivate() {
            return exceptionOnActivate;
        }

        public synchronized void setThrowExceptionOnActivate(boolean b) {
            exceptionOnActivate = b;
        }

        public synchronized void setThrowExceptionOnDestroy(boolean b) {
            exceptionOnDestroy = b;
        }

        public synchronized boolean isValidationEnabled() {
            return enableValidation;
        }

        public synchronized void setValidationEnabled(boolean b) {
            enableValidation = b;
        }

        public synchronized int getMakeCounter() {
            return makeCounter;
        }

        private void doWait(long latency) {
            try {
                Thread.sleep(latency);
            } catch (InterruptedException ex) {
                // ignore
            }
        }
    }
    @Override
    protected boolean isLifo() {
        return true;
    }

    @Override
    protected boolean isFifo() {
        return false;
    }

    /*
     * Note: This test relies on timing for correct execution. There *should* be
     * enough margin for this to work correctly on most (all?) systems but be
     * aware of this if you see a failure of this test.
     */
    @Test(timeout=60000)
    public void testBorrowObjectFairness() {

        // Config
        int numThreads = 30;
        int maxTotal = 10;

        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
            Thread t = new Thread(threads[i]);
            t.start();
            // Short delay to ensure threads start in correct order
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                fail(e.toString());
            }
        }

        // Wait for threads to finish
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    /**
     * On first borrow, first object fails validation, second object is OK.
     * Subsequent borrows are OK. This was POOL-152.
     */
    @Test(timeout=60000)
    public void testBrokenFactoryShouldNotBlockPool() {
        int maxTotal = 1;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTestOnBorrow(true);

        // First borrow object will need to create a new object which will fail
        // validation.
        String obj = null;
        Exception ex = null;
        factory.setValid(false);
        try {
            obj = pool.borrowObject();
        } catch (Exception e) {
            ex = e;
        }
        // Failure expected
        assertNotNull(ex);
        assertTrue(ex instanceof NoSuchElementException);
        assertNull(obj);

        // Configure factory to create valid objects so subsequent borrows work
        factory.setValid(true);

        // Subsequent borrows should be OK
        try {
            obj = pool.borrowObject();
        } catch (Exception e1) {
            fail();
        }
        assertNotNull(obj);
        try {
            pool.returnObject(obj);
        } catch (Exception e) {
            fail();
        }
    }

    /*
     * Very simple test thread that just tries to borrow an object from
     * the provided pool returns it after a wait
     */
    static class WaitingTestThread extends Thread {
        private final GenericObjectPool<String> _pool;
        private final long _pause;
        private Throwable _thrown;

        private long preborrow; // just before borrow
        private long postborrow; //  borrow returned
        private long postreturn; // after object was returned
        private long ended;
        private String objectId;

        public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
            _pool = pool;
            _pause = pause;
            _thrown = null;
        }

        @Override
        public void run() {
            try {
                preborrow = System.currentTimeMillis();
                String obj = _pool.borrowObject();
                objectId = obj;
                postborrow = System.currentTimeMillis();
                Thread.sleep(_pause);
                _pool.returnObject(obj);
                postreturn = System.currentTimeMillis();
            } catch (Exception e) {
                _thrown = e;
            } finally{
                ended = System.currentTimeMillis();
            }
        }
    }

    private static final boolean DISPLAY_THREAD_DETAILS=
        Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
    // To pass this to a Maven test, use:
    // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
    // @see http://jira.codehaus.org/browse/SUREFIRE-121

    /*
     * Test multi-threaded pool access.
     * Multiple threads, but maxTotal only allows half the threads to succeed.
     *
     * This test was prompted by Continuum build failures in the Commons DBCP test case:
     * TestPerUserPoolDataSource.testMultipleThreads2()
     * Let's see if the this fails on Continuum too!
     */
    @Test(timeout=60000)
    public void testMaxWaitMultiThreaded() throws Exception {
        final long maxWait = 500; // wait for connection
        final long holdTime = 2 * maxWait; // how long to hold connection
        final int threads = 10; // number of threads to grab the object initially
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(maxWait);
        pool.setMaxTotal(threads);
        // Create enough threads so half the threads will have to wait
        WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
        for(int i=0; i < wtt.length; i++){
            wtt[i] = new WaitingTestThread(pool,holdTime);
        }
        long origin = System.currentTimeMillis()-1000;
        for(int i=0; i < wtt.length; i++){
            wtt[i].start();
        }
        int failed = 0;
        for(int i=0; i < wtt.length; i++){
            wtt[i].join();
            if (wtt[i]._thrown != null){
                failed++;
            }
        }
        if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
            System.out.println(
                    "MaxWait: " + maxWait +
                    " HoldTime: " + holdTime +
                     " MaxTotal: " + threads +
                    " Threads: " + wtt.length +
                    " Failed: " + failed
                    );
            for(int i=0; i < wtt.length; i++){
                WaitingTestThread wt = wtt[i];
                System.out.println(
                        "Preborrow: " + (wt.preborrow-origin) +
                        " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
                        " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
                        " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
                        " Ended: " + (wt.ended-origin) +
                        " ObjId: " + wt.objectId
                        );
            }
        }
        assertEquals("Expected half the threads to fail",wtt.length/2,failed);
    }

    /**
     * Test the following scenario:
     *   Thread 1 borrows an instance
     *   Thread 2 starts to borrow another instance before thread 1 returns its instance
     *   Thread 1 returns its instance while thread 2 is validating its newly created instance
     * The test verifies that the instance created by Thread 2 is not leaked.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMakeConcurrentWithReturn() throws Exception {
        pool.setTestOnBorrow(true);
        factory.setValid(true);
        // Borrow and return an instance, with a short wait
        WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
        thread1.start();
        Thread.sleep(50); // wait for validation to succeed
        // Slow down validation and borrow an instance
        factory.setValidateLatency(400);
        String instance = pool.borrowObject();
        // Now make sure that we have not leaked an instance
        assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
        pool.returnObject(instance);
        assertEquals(factory.getMakeCounter(), pool.getNumIdle());
    }

    /**
     * Ensure the pool is registered.
     */
    @Test(timeout=60000)
    public void testJmxRegistration() {
        ObjectName oname = pool.getJmxName();
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(oname, null);
        Assert.assertEquals(1, result.size());
        pool.jmxUnregister();

        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setJmxEnabled(false);
        GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
        assertNull(poolWithoutJmx.getJmxName());
        config.setJmxEnabled(true);
        poolWithoutJmx.jmxUnregister();

        config.setJmxNameBase(null);
        GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
        assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a checked out object is
     * invalidated.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testInvalidateFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(500);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance
        String obj = pool.borrowObject();
        // Launch another thread - will block, but fail in 500 ms
        WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
        thread2.start();
        // Invalidate the object borrowed by this thread - should allow thread2 to create
        Thread.sleep(20);
        pool.invalidateObject(obj);
        Thread.sleep(600); // Wait for thread2 to timeout
        if (thread2._thrown != null) {
            fail(thread2._thrown.toString());
        }
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a returning object fails
     * validation.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testValidationFailureOnReturnFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        factory.setValid(false); // Validate will always fail
        factory.setValidationEnabled(true);
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(1500);
        pool.setTestOnReturn(true);
        pool.setTestOnBorrow(false);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance and return it after 500 ms (validation will fail)
        WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
        thread2.start();
        Thread.sleep(50);
        // Try to borrow an object
        String obj = pool.borrowObject();
        pool.returnObject(obj);
    }

    @Test
    public void testSwallowedExceptionListener() {
        pool.setSwallowedExceptionListener(null); // must simply return
        final List<Exception> swallowedExceptions = new ArrayList<Exception>();
        /*
         * A simple listener, that will throw a OOM on 3rd exception.
         */
        final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
            @Override
            public void onSwallowException(Exception e) {
                if (swallowedExceptions.size() == 2) {
                    throw new OutOfMemoryError();
                } else {
                    swallowedExceptions.add(e);
                }
            }
        };
        pool.setSwallowedExceptionListener(listener);

        Exception e1 = new Exception();
        Exception e2 = new ArrayIndexOutOfBoundsException();

        pool.swallowException(e1);
        pool.swallowException(e2);

        try {
            pool.swallowException(e1);
            fail("Not supposed to get here");
        } catch (OutOfMemoryError oom) {
            // expected
        }

        assertEquals(2, swallowedExceptions.size());
    }

    // POOL-248
    @Test(expected=IllegalStateException.class)
    public void testMultipleReturnOfSameObject() throws Exception {
        final GenericObjectPool<String> pool = new GenericObjectPool<String>(
                factory, new GenericObjectPoolConfig());

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        String obj = pool.borrowObject();

        Assert.assertEquals(1, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());
    }

    private static final class DummyFactory
            extends BasePooledObjectFactory<Object> {
        @Override
        public Object create() throws Exception {
            return null;
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }
    }


    private static class InvalidFactory
            extends BasePooledObjectFactory<Object> {

        @Override
        public Object create() throws Exception {
            return new Object();
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }

        @Override
        public boolean validateObject(PooledObject<Object> obj) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // Ignore
            }
            return false;
        }
    }

    private static class EvictionThread<T> extends Thread {

        private final GenericObjectPool<T> pool;

        public EvictionThread(GenericObjectPool<T> pool) {
            this.pool = pool;
        }

        @Override
        public void run() {
            try {
                pool.evict();
            } catch (Exception e) {
                // Ignore
            }
        }
    }
}

Not sure of the meaning you are inferring with 'multiplexed'

Best of Luck in Brasil
Martin 
______________________________________________ 
 _____ _          _____             _          _____     ___ _                        _____               _     _   _         
|_   _| |_ ___   |  _  |___ ___ ___| |_ ___   |   __|___|  _| |_ _ _ _ ___ ___ ___   |   __|___ _ _ ___ _| |___| |_|_|___ ___ 
  | | |   | -_|  |     | . | .'|  _|   | -_|  |__   | . |  _|  _| | | | .'|  _| -_|  |   __| . | | |   | . | .'|  _| | . |   |
  |_| |_|_|___|  |__|__|  _|__,|___|_|_|___|  |_____|___|_| |_| |_____|__,|_| |___|  |__|  |___|___|_|_|___|__,|_| |_|___|_|_|
                       |_|                                                                                                    


From: JLeskovar@telecomsys.com
To: user@commons.apache.org
Subject: Multiplexed connections in commons pool
Date: Wed, 18 Jun 2014 23:07:44 +0000









Hi there,
 
I have an application that needs to perform connection pooling, with the proviso that it's okay - and actually preferable - for more than one client to checkout and use the same connection object from the pool. Ideally, I would also like
 to limit the number of concurrent clients that are using a single connection object. I'm wondering what the best way to do this is. As a quick and dirty option, I suppose I could basically have my PooledObjectFactory return the same objects from makeObject(),
 and manually keep track of objects from inside my implementation. Thoughts?
 
Cheers,
James Leskovar

Software Engineer, Location Platforms
TeleCommunication Systems, Inc.



[ Address : TCS, iC Enterprise 1, Innovation Campus, Squires Way, Nth Wollongong, NSW, 2500, Australia ]

[ Tel : +61 2 4221 2940 ] [ Fax : +61 2 4221 2901 ] 

[ Email : James.Leskovar@telecomsys.com ]

 

CONFIDENTIALITY NOTICE: The information contained in this message may be privileged and/or confidential. If you are not the intended recipient, or responsible for delivering this message to the intended recipient, any review, forwarding, dissemination, distribution or copying of this communication or any attachment(s) is strictly prohibited. If you have received this message in error, please notify the sender immediately, and delete it and all attachments from your computer and network.
 		 	   		  

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: Multiplexed connections in commons pool

Posted by Gary Gregory <ga...@gmail.com>.
I think a link to SVN would have been enough...

Gary


On Wed, Jun 18, 2014 at 8:14 PM, Martin Gainty <mg...@hotmail.com> wrote:

> James-
> There is a nice test-case in 2.2 apache-commons that covers
> (Max-timeout-per-connection) and max-connections you are seeking:
> /*
>  * Licensed to the Apache Software Foundation (ASF) under one or more
>  * contributor license agreements.  See the NOTICE file distributed with
>  * this work for additional information regarding copyright ownership.
>  * The ASF licenses this file to You under the Apache License, Version 2.0
>  * (the "License"); you may not use this file except in compliance with
>  * the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing, software
>  * distributed under the License is distributed on an "AS IS" BASIS,
>  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  * See the License for the specific language governing permissions and
>  * limitations under the License.
>  */
>
> package org.apache.commons.pool2.impl;
>
> import static org.junit.Assert.assertEquals;
> import static org.junit.Assert.assertFalse;
> import static org.junit.Assert.assertNotNull;
> import static org.junit.Assert.assertNull;
> import static org.junit.Assert.assertTrue;
> import static org.junit.Assert.fail;
>
> import java.lang.management.ManagementFactory;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.NoSuchElementException;
> import java.util.Random;
> import java.util.Set;
> import java.util.concurrent.atomic.AtomicInteger;
>
> import javax.management.MBeanServer;
> import javax.management.ObjectName;
>
> import org.apache.commons.pool2.BasePooledObjectFactory;
> import org.apache.commons.pool2.ObjectPool;
> import org.apache.commons.pool2.PoolUtils;
> import org.apache.commons.pool2.PooledObject;
> import org.apache.commons.pool2.PooledObjectFactory;
> import org.apache.commons.pool2.SwallowedExceptionListener;
> import org.apache.commons.pool2.TestBaseObjectPool;
> import org.apache.commons.pool2.VisitTracker;
> import org.apache.commons.pool2.VisitTrackerFactory;
> import org.junit.After;
> import org.junit.Assert;
> import org.junit.Before;
> import org.junit.Test;
>
> /**
>  * @version $Revision: 1569016 $
>  */
> public class TestGenericObjectPool extends TestBaseObjectPool {
>
>     @Override
>     protected ObjectPool<String> makeEmptyPool(int mincap) {
>        GenericObjectPool<String> mtPool =
>                new GenericObjectPool<String>(new SimpleFactory());
>        mtPool.setMaxTotal(mincap);
>        mtPool.setMaxIdle(mincap);
>        return mtPool;
>     }
>
>     @Override
>     protected ObjectPool<Object> makeEmptyPool(
>             final PooledObjectFactory<Object> fac) {
>         return new GenericObjectPool<Object>(fac);
>     }
>
>     @Override
>     protected Object getNthObject(int n) {
>         return String.valueOf(n);
>     }
>
>     @Before
>     public void setUp() throws Exception {
>         factory = new SimpleFactory();
>         pool = new GenericObjectPool<String>(factory);
>     }
>
>     @After
>     public void tearDown() throws Exception {
>         String poolName = pool.getJmxName().toString();
>         pool.clear();
>         pool.close();
>         pool = null;
>         factory = null;
>
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(new ObjectName(
>                 "org.apache.commoms.pool2:type=GenericObjectPool,*"),
> null);
>         // There should be no registered pools at this point
>         int registeredPoolCount = result.size();
>         StringBuilder msg = new StringBuilder("Current pool is: ");
>         msg.append(poolName);
>         msg.append("  Still open pools are: ");
>         for (ObjectName name : result) {
>             // Clean these up ready for the next test
>             msg.append(name.toString());
>             msg.append(" created via\n");
>             msg.append(mbs.getAttribute(name, "CreationStackTrace"));
>             msg.append('\n');
>             mbs.unregisterMBean(name);
>         }
>         Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
>     }
>
>     @Test(expected=IllegalArgumentException.class)
>     public void testConstructorNullFactory() {
>         // add dummy assert (won't be invoked because of IAE) to avoid
> "unused" warning
>         assertNotNull(new GenericObjectPool<String>(null));
>         // TODO this currently causes tearDown to report an error
>         // Looks like GOP needs to call close() or jmxUnregister() before
> throwing IAE
>     }
>
>     @Test(timeout=60000)
>     public void testConstructors() throws Exception {
>
>         // Make constructor arguments all different from defaults
>         int minIdle = 2;
>         long maxWait = 3;
>         int maxIdle = 4;
>         int maxTotal = 5;
>         long minEvictableIdleTimeMillis = 6;
>         int numTestsPerEvictionRun = 7;
>         boolean testOnBorrow = true;
>         boolean testOnReturn = true;
>         boolean testWhileIdle = true;
>         long timeBetweenEvictionRunsMillis = 8;
>         boolean blockWhenExhausted = false;
>         boolean lifo = false;
>         PooledObjectFactory<Object> dummyFactory = new DummyFactory();
>         GenericObjectPool<Object> dummyPool =
>                 new GenericObjectPool<Object>(dummyFactory);
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE,
> dummyPool.getMaxIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS,
> dummyPool.getMaxWaitMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE,
> dummyPool.getMinIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL,
> dummyPool.getMaxTotal());
>
> assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>
> assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
>                 dummyPool.getNumTestsPerEvictionRun());
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>
> assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
>                 Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>
>         GenericObjectPoolConfig config =
>                 new GenericObjectPoolConfig();
>         config.setLifo(lifo);
>         config.setMaxIdle(maxIdle);
>         config.setMinIdle(minIdle);
>         config.setMaxTotal(maxTotal);
>         config.setMaxWaitMillis(maxWait);
>         config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
>         config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
>         config.setTestOnBorrow(testOnBorrow);
>         config.setTestOnReturn(testOnReturn);
>         config.setTestWhileIdle(testWhileIdle);
>
> config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
>         config.setBlockWhenExhausted(blockWhenExhausted);
>         dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
>         assertEquals(maxIdle, dummyPool.getMaxIdle());
>         assertEquals(maxWait, dummyPool.getMaxWaitMillis());
>         assertEquals(minIdle, dummyPool.getMinIdle());
>         assertEquals(maxTotal, dummyPool.getMaxTotal());
>         assertEquals(minEvictableIdleTimeMillis,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(numTestsPerEvictionRun,
> dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(testOnBorrow),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(testOnReturn),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(testWhileIdle),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(timeBetweenEvictionRunsMillis,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(blockWhenExhausted),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(lifo),
> Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testWhenExhaustedFail() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(false);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumIdle());
>         pool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlock() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(10L);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         pool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockInterupt() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         String obj1 = pool.borrowObject();
>
>         // Make sure on object was obtained
>         assertNotNull(obj1);
>
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>         wtt.interrupt();
>
>         // Give interupt time to take effect
>         Thread.sleep(200);
>
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>
>         // Return object to the pool
>         pool.returnObject(obj1);
>
>         // Bug POOL-162 - check there is now an object in the pool
>         pool.setMaxWaitMillis(10L);
>         String obj2 = null;
>         try {
>              obj2 = pool.borrowObject();
>             assertNotNull(obj2);
>         } catch(NoSuchElementException e) {
>             // Not expected
>             fail("NoSuchElementException not expected");
>         }
>         pool.returnObject(obj2);
>         pool.close();
>
>     }
>
>     @Test(timeout=60000)
>     public void testEvictWhileEmpty() throws Exception {
>         pool.evict();
>         pool.evict();
>         pool.close();
>     }
>
>     /**
>      * Tests addObject contention between ensureMinIdle triggered by
>      * the Evictor with minIdle > 0 and borrowObject.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictAddObjects() throws Exception {
>         factory.setMakeLatency(300);
>         factory.setMaxTotal(2);
>         pool.setMaxTotal(2);
>         pool.setMinIdle(1);
>         pool.borrowObject(); // numActive = 1, numIdle = 0
>         // Create a test thread that will run once and try a borrow after
>         // 150ms fixed delay
>         TestThread borrower = new TestThread(pool, 1, 150, false);
>         Thread borrowerThread = new Thread(borrower);
>         // Set evictor to run in 100 ms - will create idle instance
>         pool.setTimeBetweenEvictionRunsMillis(100);
>         borrowerThread.start();  // Off to the races
>         borrowerThread.join();
>         assertTrue(!borrower.failed());
>     }
>
>     @Test(timeout=60000)
>     public void testEvictLIFO() throws Exception {
>         checkEvict(true);
>     }
>
>     @Test(timeout=60000)
>     public void testEvictFIFO() throws Exception {
>         checkEvict(false);
>     }
>
>     private void checkEvict(boolean lifo) throws Exception {
>         // yea this is hairy but it tests all the code paths in GOP.evict()
>         pool.setSoftMinEvictableIdleTimeMillis(10);
>         pool.setMinIdle(2);
>         pool.setTestWhileIdle(true);
>         pool.setLifo(lifo);
>         PoolUtils.prefill(pool, 5);
>         pool.evict();
>         factory.setEvenValid(false);
>         factory.setOddValid(false);
>         factory.setThrowExceptionOnActivate(true);
>         pool.evict();
>         PoolUtils.prefill(pool, 5);
>         factory.setThrowExceptionOnActivate(false);
>         factory.setThrowExceptionOnPassivate(true);
>         pool.evict();
>         factory.setThrowExceptionOnPassivate(false);
>         factory.setEvenValid(true);
>         factory.setOddValid(true);
>         Thread.sleep(125);
>         pool.evict();
>         assertEquals(2, pool.getNumIdle());
>     }
>
>     /**
>      * Test to make sure evictor visits least recently used objects first,
>      * regardless of FIFO/LIFO.
>      *
>      * JIRA: POOL-86
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictionOrder() throws Exception {
>         checkEvictionOrder(false);
>         tearDown();
>         setUp();
>         checkEvictionOrder(true);
>     }
>
>     private void checkEvictionOrder(boolean lifo) throws Exception {
>         checkEvictionOrderPart1(lifo);
>         tearDown();
>         setUp();
>         checkEvictionOrderPart2(lifo);
>     }
>
>     private void checkEvictionOrderPart1(boolean lifo) throws Exception {
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         // Order, oldest to youngest, is "0", "1", ...,"4"
>         pool.evict(); // Should evict "0" and "1"
>         Object obj = pool.borrowObject();
>         assertTrue("oldest not evicted", !obj.equals("0"));
>         assertTrue("second oldest not evicted", !obj.equals("1"));
>         // 2 should be next out for FIFO, 4 for LIFO
>         assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
>     }
>
>     private void checkEvictionOrderPart2(boolean lifo) throws Exception {
>         // Two eviction runs in sequence
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         pool.evict(); // Should evict "0" and "1"
>         pool.evict(); // Should evict "2" and "3"
>         Object obj = pool.borrowObject();
>         assertEquals("Wrong instance remaining in pool", "4", obj);
>     }
>
>     /**
>      * Verifies that the evictor visits objects in expected order
>      * and frequency.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testEvictorVisiting() throws Exception {
>         checkEvictorVisiting(true);
>         checkEvictorVisiting(false);
>     }
>
>     private void checkEvictorVisiting(boolean lifo) throws Exception {
>         VisitTrackerFactory<Object> trackerFactory = new
> VisitTrackerFactory<Object>();
>         GenericObjectPool<VisitTracker<Object>> trackerPool =
>                 new
> GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(2);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // Visit oldest 2 - 0 and 1
>         VisitTracker<Object> obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         //  borrow, return, borrow, return
>         //  FIFO will move 0 and 1 to end
>         //  LIFO, 7 out, then in, then out, then in
>         trackerPool.evict();  // Should visit 2 and 3 in either case
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() >= 4) {
>                 assertEquals("Unexpected instance visited " +
> tracker.getId(),
>                         0, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
>
>         trackerFactory = new VisitTrackerFactory<Object>();
>         trackerPool = new
> GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(3);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // 0, 1, 2
>         trackerPool.evict(); // 3, 4, 5
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         // borrow, return, borrow, return
>         //  FIFO 3,4,5,6,7,0,1,2
>         //  LIFO 7,6,5,4,3,2,1,0
>         // In either case, pointer should be at 6
>         trackerPool.evict();
>         // Should hit 6,7,0 - 0 for second time
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() != 0) {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         2, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
>
>         // Randomly generate a pools with random numTests
>         // and make sure evictor cycles through elements appropriately
>         int[] smallPrimes = {2, 3, 5, 7};
>         Random random = new Random();
>         random.setSeed(System.currentTimeMillis());
>         for (int i = 0; i < 4; i++) {
>             for (int j = 0; j < 5; j++) {
>                 trackerPool = new
> GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>                 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
>                 trackerPool.setMinEvictableIdleTimeMillis(-1);
>                 trackerPool.setTestWhileIdle(true);
>                 trackerPool.setLifo(lifo);
>                 trackerPool.setTestOnReturn(false);
>                 trackerPool.setTestOnBorrow(false);
>                 trackerPool.setMaxIdle(-1);
>                 int instanceCount = 10 + random.nextInt(20);
>                 trackerPool.setMaxTotal(instanceCount);
>                 for (int k = 0; k < instanceCount; k++) {
>                     trackerPool.addObject();
>                 }
>
>                 // Execute a random number of evictor runs
>                 int runs = 10 + random.nextInt(50);
>                 for (int k = 0; k < runs; k++) {
>                     trackerPool.evict();
>                 }
>
>                 // Number of times evictor should have cycled through the
> pool
>                 int cycleCount = (runs *
> trackerPool.getNumTestsPerEvictionRun()) /
>                         instanceCount;
>
>                 // Look at elements and make sure they are visited
> cycleCount
>                 // or cycleCount + 1 times
>                 VisitTracker<Object> tracker = null;
>                 int visitCount = 0;
>                 for (int k = 0; k < instanceCount; k++) {
>                     tracker = trackerPool.borrowObject();
>                     assertTrue(trackerPool.getNumActive() <=
> trackerPool.getMaxTotal());
>                     visitCount = tracker.getValidateCount();
>                     assertTrue(visitCount >= cycleCount &&
>                             visitCount <= cycleCount + 1);
>                 }
>                 trackerPool.close();
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnPassivateDuringReturn() throws Exception {
>         String obj = pool.borrowObject();
>         factory.setThrowExceptionOnPassivate(true);
>         pool.returnObject(obj);
>         assertEquals(0,pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringBorrow() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnBorrow(true);
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail on next borrow
> attempt
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringReturn() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnReturn(true);
>         String obj1 = pool.borrowObject();
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnActivateDuringBorrow() throws Exception {
>         String obj1 = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         pool.returnObject(obj1);
>         pool.returnObject(obj2);
>         factory.setThrowExceptionOnActivate(true);
>         factory.setEvenValid(false);
>         // Activation will now throw every other time
>         // First attempt throws, but loop continues and second succeeds
>         String obj = pool.borrowObject();
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>
>         pool.returnObject(obj);
>         factory.setValid(false);
>         // Validation will now fail on activation when borrowObject returns
>         // an idle instance, and then when attempting to create a new
> instance
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(0, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testNegativeMaxTotal() throws Exception {
>         pool.setMaxTotal(-1);
>         pool.setBlockWhenExhausted(false);
>         String obj = pool.borrowObject();
>         assertEquals(getNthObject(0),obj);
>         pool.returnObject(obj);
>     }
>
>     @Test(timeout=60000)
>     public void testMaxIdle() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(8);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMaxIdleZero() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(0);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals(0, pool.getNumIdle());
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMaxTotal() throws Exception {
>         pool.setMaxTotal(3);
>         pool.setBlockWhenExhausted(false);
>
>         pool.borrowObject();
>         pool.borrowObject();
>         pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testTimeoutNoLeak() throws Exception {
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(10);
>         pool.setBlockWhenExhausted(true);
>         String obj = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         pool.returnObject(obj2);
>         pool.returnObject(obj);
>
>         pool.borrowObject();
>         pool.borrowObject();
>     }
>
>     @Test(timeout=60000)
>     public void testMaxTotalZero() throws Exception {
>         pool.setMaxTotal(0);
>         pool.setBlockWhenExhausted(false);
>
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMaxTotalUnderLoad() {
>         // Config
>         int numThreads = 199; // And main thread makes a round 200.
>         int numIter = 20;
>         int delay = 25;
>         int maxTotal = 10;
>
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
>
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             // Factor of 2 on iterations so main thread does work whilst
> other
>             // threads are running. Factor of 2 on delay so average delay
> for
>             // other threads == actual delay for main thread
>             threads[i] = new TestThread(pool, numIter * 2, delay * 2);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         // Give the threads a chance to start doing some work
>         try {
>             Thread.sleep(5000);
>         } catch(InterruptedException e) {
>             // ignored
>         }
>
>         for (int i = 0; i < numIter; i++) {
>             String obj = null;
>             try {
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 obj = pool.borrowObject();
>                 // Under load, observed _numActive > _maxTotal
>                 if (pool.getNumActive() > pool.getMaxTotal()) {
>                     throw new IllegalStateException("Too many active
> objects");
>                 }
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             } catch (Exception e) {
>                 // Shouldn't happen
>                 e.printStackTrace();
>                 fail("Exception on borrow");
>             } finally {
>                 if (obj != null) {
>                     try {
>                         pool.returnObject(obj);
>                     } catch (Exception e) {
>                         // Ignore
>                     }
>                 }
>             }
>         }
>
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testSettersAndGetters() throws Exception {
>         {
>             // The object receives an Exception during its creation to
> prevent
>             // memory leaks. See BaseGenericObjectPool constructor for
> more details.
>             assertTrue(false == "".equals(pool.getCreationStackTrace()));
>         }
>         {
>             assertEquals(0, pool.getBorrowedCount());
>         }
>         {
>             assertEquals(0, pool.getReturnedCount());
>         }
>         {
>             assertEquals(0, pool.getCreatedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByEvictorCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByBorrowValidationCount());
>         }
>         {
>             assertEquals(0, pool.getMeanActiveTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanIdleTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getNumIdle());
>         }
>         {
>             pool.setMaxTotal(123);
>             assertEquals(123,pool.getMaxTotal());
>         }
>         {
>             pool.setMaxIdle(12);
>             assertEquals(12,pool.getMaxIdle());
>         }
>         {
>             pool.setMaxWaitMillis(1234L);
>             assertEquals(1234L,pool.getMaxWaitMillis());
>         }
>         {
>             pool.setMinEvictableIdleTimeMillis(12345L);
>             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setNumTestsPerEvictionRun(11);
>             assertEquals(11,pool.getNumTestsPerEvictionRun());
>         }
>         {
>             pool.setTestOnBorrow(true);
>             assertTrue(pool.getTestOnBorrow());
>             pool.setTestOnBorrow(false);
>             assertTrue(!pool.getTestOnBorrow());
>         }
>         {
>             pool.setTestOnReturn(true);
>             assertTrue(pool.getTestOnReturn());
>             pool.setTestOnReturn(false);
>             assertTrue(!pool.getTestOnReturn());
>         }
>         {
>             pool.setTestWhileIdle(true);
>             assertTrue(pool.getTestWhileIdle());
>             pool.setTestWhileIdle(false);
>             assertTrue(!pool.getTestWhileIdle());
>         }
>         {
>             pool.setTimeBetweenEvictionRunsMillis(11235L);
>             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
>         }
>         {
>             pool.setSoftMinEvictableIdleTimeMillis(12135L);
>             assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setBlockWhenExhausted(true);
>             assertTrue(pool.getBlockWhenExhausted());
>             pool.setBlockWhenExhausted(false);
>             assertFalse(pool.getBlockWhenExhausted());
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testDefaultConfiguration() throws Exception {
>         assertConfiguration(new GenericObjectPoolConfig(),pool);
>     }
>
>     @Test(timeout=60000)
>     public void testSetConfig() throws Exception {
>         GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
>         assertConfiguration(expected,pool);
>         expected.setMaxTotal(2);
>         expected.setMaxIdle(3);
>         expected.setMaxWaitMillis(5L);
>         expected.setMinEvictableIdleTimeMillis(7L);
>         expected.setNumTestsPerEvictionRun(9);
>         expected.setTestOnCreate(true);
>         expected.setTestOnBorrow(true);
>         expected.setTestOnReturn(true);
>         expected.setTestWhileIdle(true);
>         expected.setTimeBetweenEvictionRunsMillis(11L);
>         expected.setBlockWhenExhausted(false);
>         pool.setConfig(expected);
>         assertConfiguration(expected,pool);
>     }
>
>     @Test(timeout=60000)
>     public void testStartAndStopEvictor() throws Exception {
>         // set up pool without evictor
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(6);
>         pool.setMinEvictableIdleTimeMillis(100L);
>
>         for(int j=0;j<2;j++) {
>             // populate the pool
>             {
>                 String[] active = new String[6];
>                 for(int i=0;i<6;i++) {
>                     active[i] = pool.borrowObject();
>                 }
>                 for(int i=0;i<6;i++) {
>                     pool.returnObject(active[i]);
>                 }
>             }
>
>             // note that it stays populated
>             assertEquals("Should have 6 idle",6,pool.getNumIdle());
>
>             // start the evictor
>             pool.setTimeBetweenEvictionRunsMillis(50L);
>
>             // wait a second (well, .2 seconds)
>             try { Thread.sleep(200L); } catch(InterruptedException e) { }
>
>             // assert that the evictor has cleared out the pool
>             assertEquals("Should have 0 idle",0,pool.getNumIdle());
>
>             // stop the evictor
>             pool.startEvictor(0L);
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testEvictionWithNegativeNumTests() throws Exception {
>         // when numTestsPerEvictionRun is negative, it represents a
> fraction of the idle objects to test
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(-2);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>
>         String[] active = new String[6];
>         for(int i=0;i<6;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<6;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 6 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() <= 6);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 3 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() <= 3);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should be at most 2 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() <= 2);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " +
> pool.getNumIdle(),0,pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testEviction() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(100);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
>
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " +
> pool.getNumIdle(),0,pool.getNumIdle());
>
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " +
> pool.getNumIdle(),0,pool.getNumIdle());
>     }
>
>     public static class TestEvictionPolicy<T> implements EvictionPolicy<T>
> {
>
>         private AtomicInteger callCount = new AtomicInteger(0);
>
>         @Override
>         public boolean evict(EvictionConfig config, PooledObject<T>
> underTest,
>                 int idleCount) {
>             if (callCount.incrementAndGet() > 1500) {
>                 return true;
>             } else {
>                 return false;
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testEvictionPolicy() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(500);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
>
>         // ClassNotFoundException
>         try {
>
> pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
>             fail("setEvictionPolicyClassName must throw an error if the
> class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
>
>         // InstantiationException
>         try {
>
> pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the
> class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
>
>         // IllegalAccessException
>         try {
>
> pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the
> class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
>
>
> pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
>         assertEquals(TestEvictionPolicy.class.getName(),
> pool.getEvictionPolicyClassName());
>
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         // Eviction policy ignores first 1500 attempts to evict and then
> always
>         // evicts. After 1s, there should have been two runs of 500 tests
> so no
>         // evictions
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 500 idle", 500, pool.getNumIdle());
>         // A further 1s wasn't enough so allow 2s for the evictor to clear
> out
>         // all of the idle objects.
>         try { Thread.sleep(2000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 0 idle", 0, pool.getNumIdle());
>     }
>
>
>     @Test(timeout=60000)
>     public void testEvictionSoftMinIdle() throws Exception {
>         class TimeTest extends BasePooledObjectFactory<TimeTest> {
>             private final long createTime;
>             public TimeTest() {
>                 createTime = System.currentTimeMillis();
>             }
>             @Override
>             public TimeTest create() throws Exception {
>                 return new TimeTest();
>             }
>             @Override
>             public PooledObject<TimeTest> wrap(TimeTest value) {
>                 return new DefaultPooledObject<TimeTest>(value);
>             }
>             public long getCreateTime() {
>                 return createTime;
>             }
>         }
>
>         GenericObjectPool<TimeTest> timePool =
>             new GenericObjectPool<TimeTest>(new TimeTest());
>
>         timePool.setMaxIdle(5);
>         timePool.setMaxTotal(5);
>         timePool.setNumTestsPerEvictionRun(5);
>         timePool.setMinEvictableIdleTimeMillis(3000L);
>         timePool.setSoftMinEvictableIdleTimeMillis(1000L);
>         timePool.setMinIdle(2);
>
>         TimeTest[] active = new TimeTest[5];
>         Long[] creationTime = new Long[5] ;
>         for(int i=0;i<5;i++) {
>             active[i] = timePool.borrowObject();
>             creationTime[i] = Long.valueOf((active[i]).getCreateTime());
>         }
>
>         for(int i=0;i<5;i++) {
>             timePool.returnObject(active[i]);
>         }
>
>         // Soft evict all but minIdle(2)
>         Thread.sleep(1500L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 2,
> timePool.getNumIdle());
>
>         // Hard evict the rest.
>         Thread.sleep(2000L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 0,
> timePool.getNumIdle());
>         timePool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testEvictionInvalid() throws Exception {
>
>         final GenericObjectPool<Object> invalidFactoryPool =
>                 new GenericObjectPool<Object>(new InvalidFactory());
>
>         invalidFactoryPool.setMaxIdle(1);
>         invalidFactoryPool.setMaxTotal(1);
>         invalidFactoryPool.setTestOnBorrow(false);
>         invalidFactoryPool.setTestOnReturn(false);
>         invalidFactoryPool.setTestWhileIdle(true);
>         invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
>         invalidFactoryPool.setNumTestsPerEvictionRun(1);
>
>         Object p = invalidFactoryPool.borrowObject();
>         invalidFactoryPool.returnObject(p);
>
>         // Run eviction in a separate thread
>         Thread t = new EvictionThread<Object>(invalidFactoryPool);
>         t.start();
>
>         // Sleep to make sure evictor has started
>         Thread.sleep(300);
>
>         try {
>             invalidFactoryPool.borrowObject(1);
>         } catch (NoSuchElementException nsee) {
>             // Ignore
>         }
>
>         // Make sure evictor has finished
>         Thread.sleep(1000);
>
>         // Should have an empty pool
>         assertEquals("Idle count different than expected.", 0,
> invalidFactoryPool.getNumIdle());
>         assertEquals("Total count different than expected.", 0,
> invalidFactoryPool.getNumActive());
>         invalidFactoryPool.close();
>     }
>
>     /**
>      * POOL-231 - verify that concurrent invalidates of the same object do
> not
>      * corrupt pool destroyCount.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testConcurrentInvalidate() throws Exception {
>         // Get allObjects and idleObjects loaded with some instances
>         final int nObjects = 1000;
>         pool.setMaxTotal(nObjects);
>         pool.setMaxIdle(nObjects);
>         final String[] obj = new String[nObjects];
>         for (int i = 0; i < nObjects; i++) {
>             obj[i] = pool.borrowObject();
>         }
>         for (int i = 0; i < nObjects; i++) {
>             if (i % 2 == 0) {
>                 pool.returnObject(obj[i]);
>             }
>         }
>         final int nThreads = 20;
>         final int nIterations = 60;
>         final InvalidateThread[] threads = new InvalidateThread[nThreads];
>         // Randomly generated list of distinct invalidation targets
>         final ArrayList<Integer> targets = new ArrayList<Integer>();
>         final Random random = new Random();
>         for (int j = 0; j < nIterations; j++) {
>             // Get a random invalidation target
>             Integer targ = Integer.valueOf(random.nextInt(nObjects));
>             while (targets.contains(targ)) {
>                 targ = Integer.valueOf(random.nextInt(nObjects));
>             }
>             targets.add(targ);
>             // Launch nThreads threads all trying to invalidate the target
>             for (int i = 0; i < nThreads; i++) {
>                 threads[i] = new InvalidateThread(pool,
> obj[targ.intValue()]);
>             }
>             for (int i = 0; i < nThreads; i++) {
>                 new Thread(threads[i]).start();
>             }
>             boolean done = false;
>             while (!done) {
>                 done = true;
>                 for (int i = 0; i < nThreads; i++) {
>                     done = done && threads[i].complete();
>                 }
>                 Thread.sleep(100);
>             }
>         }
>         Assert.assertEquals(nIterations, pool.getDestroyedCount());
>     }
>
>     /**
>      * Attempts to invalidate an object, swallowing IllegalStateException.
>      */
>     static class InvalidateThread implements Runnable {
>         private final String obj;
>         private final ObjectPool<String> pool;
>         private boolean done = false;
>         public InvalidateThread(ObjectPool<String> pool, String obj) {
>             this.obj = obj;
>             this.pool = pool;
>         }
>         @Override
>         public void run() {
>             try {
>                 pool.invalidateObject(obj);
>             } catch (IllegalStateException ex) {
>                 // Ignore
>             } catch (Exception ex) {
>                 Assert.fail("Unexpected exception " + ex.toString());
>             } finally {
>                 done = true;
>             }
>         }
>         public boolean complete() {
>             return done;
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMinIdle() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         String[] active = new String[5];
>         active[0] = pool.borrowObject();
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=1 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
>
>     @Test(timeout=60000)
>     public void testMinIdleMaxTotal() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         String[] active = new String[10];
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=0 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 10);
>
>         for(int i=0 ; i<10 ; i++) {
>             active[i] = pool.borrowObject();
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 0 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 0);
>
>         for(int i=0 ; i<10 ; i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
>
>     /**
>      * Kicks off <numThreads> test threads, each of which will go through
>      * <iterations> borrow-return cycles with random delay times <= delay
>      * in between.
>      */
>     private void runTestThreads(int numThreads, int iterations, int delay)
> {
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool,iterations,delay);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testThreaded1() throws Exception {
>         pool.setMaxTotal(15);
>         pool.setMaxIdle(15);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(20, 100, 50);
>     }
>
>     /**
>      * Verifies that maxTotal is not exceeded when factory destroyObject
>      * has high latency, testOnReturn is set and there is high incidence of
>      * validation failures.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMaxTotalInvariant() throws Exception {
>         int maxTotal = 15;
>         factory.setEvenValid(false);     // Every other validation fails
>         factory.setDestroyLatency(100);  // Destroy takes 100 ms
>         factory.setMaxTotal(maxTotal); // (makes - destroys) bound
>         factory.setValidationEnabled(true);
>         pool.setMaxTotal(maxTotal);
>         pool.setMaxIdle(-1);
>         pool.setTestOnReturn(true);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(5, 10, 50);
>     }
>
>     @Test(timeout=60000)
>     public void testConcurrentBorrowAndEvict() throws Exception {
>
>         pool.setMaxTotal(1);
>         pool.addObject();
>
>         for( int i=0; i<5000; i++) {
>             ConcurrentBorrowAndEvictThread one =
>                     new ConcurrentBorrowAndEvictThread(true);
>             ConcurrentBorrowAndEvictThread two =
>                     new ConcurrentBorrowAndEvictThread(false);
>
>             one.start();
>             two.start();
>             one.join();
>             two.join();
>
>             pool.returnObject(one.obj);
>
>             /* Uncomment this for a progress indication
>             if (i % 10 == 0) {
>                 System.out.println(i/10);
>             }
>             */
>         }
>     }
>
>     /**
>      * POOL-189
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockClosePool() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         Object obj1 = pool.borrowObject();
>
>         // Make sure an object was obtained
>         assertNotNull(obj1);
>
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>
>         // close the pool (Bug POOL-189)
>         pool.close();
>
>         // Give interrupt time to take effect
>         Thread.sleep(200);
>
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>     }
>
>     private class ConcurrentBorrowAndEvictThread extends Thread {
>         private boolean borrow;
>         public String obj;
>
>         public ConcurrentBorrowAndEvictThread(boolean borrow) {
>             this.borrow = borrow;
>         }
>
>         @Override
>         public void run() {
>             try {
>                 if (borrow) {
>                     obj = pool.borrowObject();
>                 } else {
>                     pool.evict();
>                 }
>             } catch (Exception e) { /* Ignore */}
>         }
>     }
>
>     static class TestThread implements Runnable {
>         private final java.util.Random _random = new java.util.Random();
>
>         // Thread config items
>         private final ObjectPool<String> _pool;
>         private final int _iter;
>         private final int _delay;
>         private final boolean _randomDelay;
>         private final Object _expectedObject;
>
>         private volatile boolean _complete = false;
>         private volatile boolean _failed = false;
>         private volatile Throwable _error;
>
>         public TestThread(ObjectPool<String> pool) {
>             this(pool, 100, 50, true, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter) {
>             this(pool, iter, 50, true, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter, int delay) {
>             this(pool, iter, delay, true, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay) {
>             this(pool, iter, delay, randomDelay, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay, Object obj) {
>             _pool = pool;
>             _iter = iter;
>             _delay = delay;
>             _randomDelay = randomDelay;
>             _expectedObject = obj;
>         }
>
>         public boolean complete() {
>             return _complete;
>         }
>
>         public boolean failed() {
>             return _failed;
>         }
>
>         @Override
>         public void run() {
>             for(int i=0;i<_iter;i++) {
>                 long delay =
>                     _randomDelay ? (long)_random.nextInt(_delay) : _delay;
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 String obj = null;
>                 try {
>                     obj = _pool.borrowObject();
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>
>                 if (_expectedObject != null &&
> !_expectedObject.equals(obj)) {
>                     _error = new Throwable("Expected: "+_expectedObject+ "
> found: "+obj);
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 try {
>                     _pool.returnObject(obj);
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>             }
>             _complete = true;
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testFIFO() throws Exception {
>         String o = null;
>         pool.setLifo(false);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Oldest", "0", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Youngest", "2", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
>
>     @Test(timeout=60000)
>     public void testLIFO() throws Exception {
>         String o = null;
>         pool.setLifo(true);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Youngest", "2", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Oldest", "0", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
>
>     @Test(timeout=60000)
>     public void testAddObject() throws Exception {
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         pool.addObject();
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>         String obj = pool.borrowObject();
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         assertEquals("should be one active", 1, pool.getNumActive());
>         pool.returnObject(obj);
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>     }
>
>     protected GenericObjectPool<String> pool = null;
>
>     private SimpleFactory factory = null;
>
>     private void assertConfiguration(GenericObjectPoolConfig expected,
> GenericObjectPool<?> actual) throws Exception {
>
> assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
>                 Boolean.valueOf(actual.getTestOnCreate()));
>
> assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
>                 Boolean.valueOf(actual.getTestOnBorrow()));
>
> assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
>                 Boolean.valueOf(actual.getTestOnReturn()));
>
> assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
>                 Boolean.valueOf(actual.getTestWhileIdle()));
>         assertEquals("whenExhaustedAction",
>                 Boolean.valueOf(expected.getBlockWhenExhausted()),
>                 Boolean.valueOf(actual.getBlockWhenExhausted()));
>
> assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
>         assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
>
> assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
>
> assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
>
> assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
>
> assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
>     }
>
>     public static class SimpleFactory implements
> PooledObjectFactory<String> {
>         public SimpleFactory() {
>             this(true);
>         }
>         public SimpleFactory(boolean valid) {
>             this(valid,valid);
>         }
>         public SimpleFactory(boolean evalid, boolean ovalid) {
>             evenValid = evalid;
>             oddValid = ovalid;
>         }
>         public synchronized void setValid(boolean valid) {
>             setEvenValid(valid);
>             setOddValid(valid);
>         }
>         public synchronized void setEvenValid(boolean valid) {
>             evenValid = valid;
>         }
>         public synchronized void setOddValid(boolean valid) {
>             oddValid = valid;
>         }
>         public synchronized void setThrowExceptionOnPassivate(boolean
> bool) {
>             exceptionOnPassivate = bool;
>         }
>         public synchronized void setMaxTotal(int maxTotal) {
>             this.maxTotal = maxTotal;
>         }
>         public synchronized void setDestroyLatency(long destroyLatency) {
>             this.destroyLatency = destroyLatency;
>         }
>         public synchronized void setMakeLatency(long makeLatency) {
>             this.makeLatency = makeLatency;
>         }
>         public synchronized void setValidateLatency(long validateLatency) {
>             this.validateLatency = validateLatency;
>         }
>         @Override
>         public PooledObject<String> makeObject() {
>             final long waitLatency;
>             synchronized(this) {
>                 activeCount++;
>                 if (activeCount > maxTotal) {
>                     throw new IllegalStateException(
>                         "Too many active instances: " + activeCount);
>                 }
>                 waitLatency = makeLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             final int counter;
>             synchronized(this) {
>                 counter = makeCounter++;
>             }
>             return new
> DefaultPooledObject<String>(String.valueOf(counter));
>         }
>         @Override
>         public void destroyObject(PooledObject<String> obj) throws
> Exception {
>             final long waitLatency;
>             final boolean hurl;
>             synchronized(this) {
>                 waitLatency = destroyLatency;
>                 hurl = exceptionOnDestroy;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             synchronized(this) {
>                 activeCount--;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         @Override
>         public boolean validateObject(PooledObject<String> obj) {
>             final boolean validate;
>             final boolean evenTest;
>             final boolean oddTest;
>             final long waitLatency;
>             final int counter;
>             synchronized(this) {
>                 validate = enableValidation;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>                 waitLatency = validateLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             if (validate) {
>                 return counter%2 == 0 ? evenTest : oddTest;
>             }
>             else {
>                 return true;
>             }
>         }
>         @Override
>         public void activateObject(PooledObject<String> obj) throws
> Exception {
>             final boolean hurl;
>             final boolean evenTest;
>             final boolean oddTest;
>             final int counter;
>             synchronized(this) {
>                 hurl = exceptionOnActivate;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>             }
>             if (hurl) {
>                 if (!(counter%2 == 0 ? evenTest : oddTest)) {
>                     throw new Exception();
>                 }
>             }
>         }
>         @Override
>         public void passivateObject(PooledObject<String> obj) throws
> Exception {
>             final boolean hurl;
>             synchronized(this) {
>                 hurl = exceptionOnPassivate;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         int makeCounter = 0;
>         int validateCounter = 0;
>         int activeCount = 0;
>         boolean evenValid = true;
>         boolean oddValid = true;
>         boolean exceptionOnPassivate = false;
>         boolean exceptionOnActivate = false;
>         boolean exceptionOnDestroy = false;
>         boolean enableValidation = true;
>         long destroyLatency = 0;
>         long makeLatency = 0;
>         long validateLatency = 0;
>         int maxTotal = Integer.MAX_VALUE;
>
>         public synchronized boolean isThrowExceptionOnActivate() {
>             return exceptionOnActivate;
>         }
>
>         public synchronized void setThrowExceptionOnActivate(boolean b) {
>             exceptionOnActivate = b;
>         }
>
>         public synchronized void setThrowExceptionOnDestroy(boolean b) {
>             exceptionOnDestroy = b;
>         }
>
>         public synchronized boolean isValidationEnabled() {
>             return enableValidation;
>         }
>
>         public synchronized void setValidationEnabled(boolean b) {
>             enableValidation = b;
>         }
>
>         public synchronized int getMakeCounter() {
>             return makeCounter;
>         }
>
>         private void doWait(long latency) {
>             try {
>                 Thread.sleep(latency);
>             } catch (InterruptedException ex) {
>                 // ignore
>             }
>         }
>     }
>     @Override
>     protected boolean isLifo() {
>         return true;
>     }
>
>     @Override
>     protected boolean isFifo() {
>         return false;
>     }
>
>     /*
>      * Note: This test relies on timing for correct execution. There
> *should* be
>      * enough margin for this to work correctly on most (all?) systems but
> be
>      * aware of this if you see a failure of this test.
>      */
>     @Test(timeout=60000)
>     public void testBorrowObjectFairness() {
>
>         // Config
>         int numThreads = 30;
>         int maxTotal = 10;
>
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
>
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool, 1, 2000, false,
> String.valueOf(i % maxTotal));
>             Thread t = new Thread(threads[i]);
>             t.start();
>             // Short delay to ensure threads start in correct order
>             try {
>                 Thread.sleep(50);
>             } catch (InterruptedException e) {
>                 fail(e.toString());
>             }
>         }
>
>         // Wait for threads to finish
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
>
>     /**
>      * On first borrow, first object fails validation, second object is OK.
>      * Subsequent borrows are OK. This was POOL-152.
>      */
>     @Test(timeout=60000)
>     public void testBrokenFactoryShouldNotBlockPool() {
>         int maxTotal = 1;
>
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTestOnBorrow(true);
>
>         // First borrow object will need to create a new object which will
> fail
>         // validation.
>         String obj = null;
>         Exception ex = null;
>         factory.setValid(false);
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e) {
>             ex = e;
>         }
>         // Failure expected
>         assertNotNull(ex);
>         assertTrue(ex instanceof NoSuchElementException);
>         assertNull(obj);
>
>         // Configure factory to create valid objects so subsequent borrows
> work
>         factory.setValid(true);
>
>         // Subsequent borrows should be OK
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e1) {
>             fail();
>         }
>         assertNotNull(obj);
>         try {
>             pool.returnObject(obj);
>         } catch (Exception e) {
>             fail();
>         }
>     }
>
>     /*
>      * Very simple test thread that just tries to borrow an object from
>      * the provided pool returns it after a wait
>      */
>     static class WaitingTestThread extends Thread {
>         private final GenericObjectPool<String> _pool;
>         private final long _pause;
>         private Throwable _thrown;
>
>         private long preborrow; // just before borrow
>         private long postborrow; //  borrow returned
>         private long postreturn; // after object was returned
>         private long ended;
>         private String objectId;
>
>         public WaitingTestThread(GenericObjectPool<String> pool, long
> pause) {
>             _pool = pool;
>             _pause = pause;
>             _thrown = null;
>         }
>
>         @Override
>         public void run() {
>             try {
>                 preborrow = System.currentTimeMillis();
>                 String obj = _pool.borrowObject();
>                 objectId = obj;
>                 postborrow = System.currentTimeMillis();
>                 Thread.sleep(_pause);
>                 _pool.returnObject(obj);
>                 postreturn = System.currentTimeMillis();
>             } catch (Exception e) {
>                 _thrown = e;
>             } finally{
>                 ended = System.currentTimeMillis();
>             }
>         }
>     }
>
>     private static final boolean DISPLAY_THREAD_DETAILS=
>
> Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details",
> "false")).booleanValue();
>     // To pass this to a Maven test, use:
>     // mvn test
> -DargLine="-DTestGenericObjectPool.display.thread.details=true"
>     // @see http://jira.codehaus.org/browse/SUREFIRE-121
>
>     /*
>      * Test multi-threaded pool access.
>      * Multiple threads, but maxTotal only allows half the threads to
> succeed.
>      *
>      * This test was prompted by Continuum build failures in the Commons
> DBCP test case:
>      * TestPerUserPoolDataSource.testMultipleThreads2()
>      * Let's see if the this fails on Continuum too!
>      */
>     @Test(timeout=60000)
>     public void testMaxWaitMultiThreaded() throws Exception {
>         final long maxWait = 500; // wait for connection
>         final long holdTime = 2 * maxWait; // how long to hold connection
>         final int threads = 10; // number of threads to grab the object
> initially
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(maxWait);
>         pool.setMaxTotal(threads);
>         // Create enough threads so half the threads will have to wait
>         WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
>         for(int i=0; i < wtt.length; i++){
>             wtt[i] = new WaitingTestThread(pool,holdTime);
>         }
>         long origin = System.currentTimeMillis()-1000;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].start();
>         }
>         int failed = 0;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].join();
>             if (wtt[i]._thrown != null){
>                 failed++;
>             }
>         }
>         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
>             System.out.println(
>                     "MaxWait: " + maxWait +
>                     " HoldTime: " + holdTime +
>                      " MaxTotal: " + threads +
>                     " Threads: " + wtt.length +
>                     " Failed: " + failed
>                     );
>             for(int i=0; i < wtt.length; i++){
>                 WaitingTestThread wt = wtt[i];
>                 System.out.println(
>                         "Preborrow: " + (wt.preborrow-origin) +
>                         " Postborrow: " + (wt.postborrow != 0 ?
> wt.postborrow-origin : -1) +
>                         " BorrowTime: " + (wt.postborrow != 0 ?
> wt.postborrow-wt.preborrow : -1) +
>                         " PostReturn: " + (wt.postreturn != 0 ?
> wt.postreturn-origin : -1) +
>                         " Ended: " + (wt.ended-origin) +
>                         " ObjId: " + wt.objectId
>                         );
>             }
>         }
>         assertEquals("Expected half the threads to
> fail",wtt.length/2,failed);
>     }
>
>     /**
>      * Test the following scenario:
>      *   Thread 1 borrows an instance
>      *   Thread 2 starts to borrow another instance before thread 1
> returns its instance
>      *   Thread 1 returns its instance while thread 2 is validating its
> newly created instance
>      * The test verifies that the instance created by Thread 2 is not
> leaked.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMakeConcurrentWithReturn() throws Exception {
>         pool.setTestOnBorrow(true);
>         factory.setValid(true);
>         // Borrow and return an instance, with a short wait
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
>         thread1.start();
>         Thread.sleep(50); // wait for validation to succeed
>         // Slow down validation and borrow an instance
>         factory.setValidateLatency(400);
>         String instance = pool.borrowObject();
>         // Now make sure that we have not leaked an instance
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
>         pool.returnObject(instance);
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle());
>     }
>
>     /**
>      * Ensure the pool is registered.
>      */
>     @Test(timeout=60000)
>     public void testJmxRegistration() {
>         ObjectName oname = pool.getJmxName();
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(oname, null);
>         Assert.assertEquals(1, result.size());
>         pool.jmxUnregister();
>
>         GenericObjectPoolConfig config = new GenericObjectPoolConfig();
>         config.setJmxEnabled(false);
>         GenericObjectPool<String> poolWithoutJmx = new
> GenericObjectPool<String>(factory, config);
>         assertNull(poolWithoutJmx.getJmxName());
>         config.setJmxEnabled(true);
>         poolWithoutJmx.jmxUnregister();
>
>         config.setJmxNameBase(null);
>         GenericObjectPool<String> poolWithDefaultJmxNameBase = new
> GenericObjectPool<String>(factory, config);
>         assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
>     }
>
>     /**
>      * Verify that threads waiting on a depleted pool get served when a
> checked out object is
>      * invalidated.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testInvalidateFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         GenericObjectPool<String> pool = new
> GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(500);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance
>         String obj = pool.borrowObject();
>         // Launch another thread - will block, but fail in 500 ms
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
>         thread2.start();
>         // Invalidate the object borrowed by this thread - should allow
> thread2 to create
>         Thread.sleep(20);
>         pool.invalidateObject(obj);
>         Thread.sleep(600); // Wait for thread2 to timeout
>         if (thread2._thrown != null) {
>             fail(thread2._thrown.toString());
>         }
>     }
>
>     /**
>      * Verify that threads waiting on a depleted pool get served when a
> returning object fails
>      * validation.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testValidationFailureOnReturnFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         factory.setValid(false); // Validate will always fail
>         factory.setValidationEnabled(true);
>         GenericObjectPool<String> pool = new
> GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(1500);
>         pool.setTestOnReturn(true);
>         pool.setTestOnBorrow(false);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance and return it after 500 ms (validation
> will fail)
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
>         thread2.start();
>         Thread.sleep(50);
>         // Try to borrow an object
>         String obj = pool.borrowObject();
>         pool.returnObject(obj);
>     }
>
>     @Test
>     public void testSwallowedExceptionListener() {
>         pool.setSwallowedExceptionListener(null); // must simply return
>         final List<Exception> swallowedExceptions = new
> ArrayList<Exception>();
>         /*
>          * A simple listener, that will throw a OOM on 3rd exception.
>          */
>         final SwallowedExceptionListener listener = new
> SwallowedExceptionListener() {
>             @Override
>             public void onSwallowException(Exception e) {
>                 if (swallowedExceptions.size() == 2) {
>                     throw new OutOfMemoryError();
>                 } else {
>                     swallowedExceptions.add(e);
>                 }
>             }
>         };
>         pool.setSwallowedExceptionListener(listener);
>
>         Exception e1 = new Exception();
>         Exception e2 = new ArrayIndexOutOfBoundsException();
>
>         pool.swallowException(e1);
>         pool.swallowException(e2);
>
>         try {
>             pool.swallowException(e1);
>             fail("Not supposed to get here");
>         } catch (OutOfMemoryError oom) {
>             // expected
>         }
>
>         assertEquals(2, swallowedExceptions.size());
>     }
>
>     // POOL-248
>     @Test(expected=IllegalStateException.class)
>     public void testMultipleReturnOfSameObject() throws Exception {
>         final GenericObjectPool<String> pool = new
> GenericObjectPool<String>(
>                 factory, new GenericObjectPoolConfig());
>
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
>
>         String obj = pool.borrowObject();
>
>         Assert.assertEquals(1, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
>
>         pool.returnObject(obj);
>
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>
>         pool.returnObject(obj);
>
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>     }
>
>     private static final class DummyFactory
>             extends BasePooledObjectFactory<Object> {
>         @Override
>         public Object create() throws Exception {
>             return null;
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>     }
>
>
>     private static class InvalidFactory
>             extends BasePooledObjectFactory<Object> {
>
>         @Override
>         public Object create() throws Exception {
>             return new Object();
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>
>         @Override
>         public boolean validateObject(PooledObject<Object> obj) {
>             try {
>                 Thread.sleep(1000);
>             } catch (InterruptedException e) {
>                 // Ignore
>             }
>             return false;
>         }
>     }
>
>     private static class EvictionThread<T> extends Thread {
>
>         private final GenericObjectPool<T> pool;
>
>         public EvictionThread(GenericObjectPool<T> pool) {
>             this.pool = pool;
>         }
>
>         @Override
>         public void run() {
>             try {
>                 pool.evict();
>             } catch (Exception e) {
>                 // Ignore
>             }
>         }
>     }
> }
> /*
>  * Licensed to the Apache Software Foundation (ASF) under one or more
>  * contributor license agreements.  See the NOTICE file distributed with
>  * this work for additional information regarding copyright ownership.
>  * The ASF licenses this file to You under the Apache License, Version 2.0
>  * (the "License"); you may not use this file except in compliance with
>  * the License.  You may obtain a copy of the License at
>  *
>  *      http://www.apache.org/licenses/LICENSE-2.0
>  *
>  * Unless required by applicable law or agreed to in writing, software
>  * distributed under the License is distributed on an "AS IS" BASIS,
>  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
>  * See the License for the specific language governing permissions and
>  * limitations under the License.
>  */
>
> package org.apache.commons.pool2.impl;
>
> import static org.junit.Assert.assertEquals;
> import static org.junit.Assert.assertFalse;
> import static org.junit.Assert.assertNotNull;
> import static org.junit.Assert.assertNull;
> import static org.junit.Assert.assertTrue;
> import static org.junit.Assert.fail;
>
> import java.lang.management.ManagementFactory;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.NoSuchElementException;
> import java.util.Random;
> import java.util.Set;
> import java.util.concurrent.atomic.AtomicInteger;
>
> import javax.management.MBeanServer;
> import javax.management.ObjectName;
>
> import org.apache.commons.pool2.BasePooledObjectFactory;
> import org.apache.commons.pool2.ObjectPool;
> import org.apache.commons.pool2.PoolUtils;
> import org.apache.commons.pool2.PooledObject;
> import org.apache.commons.pool2.PooledObjectFactory;
> import org.apache.commons.pool2.SwallowedExceptionListener;
> import org.apache.commons.pool2.TestBaseObjectPool;
> import org.apache.commons.pool2.VisitTracker;
> import org.apache.commons.pool2.VisitTrackerFactory;
> import org.junit.After;
> import org.junit.Assert;
> import org.junit.Before;
> import org.junit.Test;
>
> /**
>  * @version $Revision: 1569016 $
>  */
> public class TestGenericObjectPool extends TestBaseObjectPool {
>
>     @Override
>     protected ObjectPool<String> makeEmptyPool(int mincap) {
>        GenericObjectPool<String> mtPool =
>                new GenericObjectPool<String>(new SimpleFactory());
>        mtPool.setMaxTotal(mincap);
>        mtPool.setMaxIdle(mincap);
>        return mtPool;
>     }
>
>     @Override
>     protected ObjectPool<Object> makeEmptyPool(
>             final PooledObjectFactory<Object> fac) {
>         return new GenericObjectPool<Object>(fac);
>     }
>
>     @Override
>     protected Object getNthObject(int n) {
>         return String.valueOf(n);
>     }
>
>     @Before
>     public void setUp() throws Exception {
>         factory = new SimpleFactory();
>         pool = new GenericObjectPool<String>(factory);
>     }
>
>     @After
>     public void tearDown() throws Exception {
>         String poolName = pool.getJmxName().toString();
>         pool.clear();
>         pool.close();
>         pool = null;
>         factory = null;
>
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(new ObjectName(
>                 "org.apache.commoms.pool2:type=GenericObjectPool,*"),
> null);
>         // There should be no registered pools at this point
>         int registeredPoolCount = result.size();
>         StringBuilder msg = new StringBuilder("Current pool is: ");
>         msg.append(poolName);
>         msg.append("  Still open pools are: ");
>         for (ObjectName name : result) {
>             // Clean these up ready for the next test
>             msg.append(name.toString());
>             msg.append(" created via\n");
>             msg.append(mbs.getAttribute(name, "CreationStackTrace"));
>             msg.append('\n');
>             mbs.unregisterMBean(name);
>         }
>         Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
>     }
>
>     @Test(expected=IllegalArgumentException.class)
>     public void testConstructorNullFactory() {
>         // add dummy assert (won't be invoked because of IAE) to avoid
> "unused" warning
>         assertNotNull(new GenericObjectPool<String>(null));
>         // TODO this currently causes tearDown to report an error
>         // Looks like GOP needs to call close() or jmxUnregister() before
> throwing IAE
>     }
>
>     @Test(timeout=60000)
>     public void testConstructors() throws Exception {
>
>         // Make constructor arguments all different from defaults
>         int minIdle = 2;
>         long maxWait = 3;
>         int maxIdle = 4;
>         int maxTotal = 5;
>         long minEvictableIdleTimeMillis = 6;
>         int numTestsPerEvictionRun = 7;
>         boolean testOnBorrow = true;
>         boolean testOnReturn = true;
>         boolean testWhileIdle = true;
>         long timeBetweenEvictionRunsMillis = 8;
>         boolean blockWhenExhausted = false;
>         boolean lifo = false;
>         PooledObjectFactory<Object> dummyFactory = new DummyFactory();
>         GenericObjectPool<Object> dummyPool =
>                 new GenericObjectPool<Object>(dummyFactory);
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE,
> dummyPool.getMaxIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS,
> dummyPool.getMaxWaitMillis());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE,
> dummyPool.getMinIdle());
>         assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL,
> dummyPool.getMaxTotal());
>
> assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>
> assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
>                 dummyPool.getNumTestsPerEvictionRun());
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>
> assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>
> assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
>                 Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>
>         GenericObjectPoolConfig config =
>                 new GenericObjectPoolConfig();
>         config.setLifo(lifo);
>         config.setMaxIdle(maxIdle);
>         config.setMinIdle(minIdle);
>         config.setMaxTotal(maxTotal);
>         config.setMaxWaitMillis(maxWait);
>         config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
>         config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
>         config.setTestOnBorrow(testOnBorrow);
>         config.setTestOnReturn(testOnReturn);
>         config.setTestWhileIdle(testWhileIdle);
>
> config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
>         config.setBlockWhenExhausted(blockWhenExhausted);
>         dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
>         assertEquals(maxIdle, dummyPool.getMaxIdle());
>         assertEquals(maxWait, dummyPool.getMaxWaitMillis());
>         assertEquals(minIdle, dummyPool.getMinIdle());
>         assertEquals(maxTotal, dummyPool.getMaxTotal());
>         assertEquals(minEvictableIdleTimeMillis,
>                 dummyPool.getMinEvictableIdleTimeMillis());
>         assertEquals(numTestsPerEvictionRun,
> dummyPool.getNumTestsPerEvictionRun());
>         assertEquals(Boolean.valueOf(testOnBorrow),
>                 Boolean.valueOf(dummyPool.getTestOnBorrow()));
>         assertEquals(Boolean.valueOf(testOnReturn),
>                 Boolean.valueOf(dummyPool.getTestOnReturn()));
>         assertEquals(Boolean.valueOf(testWhileIdle),
>                 Boolean.valueOf(dummyPool.getTestWhileIdle()));
>         assertEquals(timeBetweenEvictionRunsMillis,
>                 dummyPool.getTimeBetweenEvictionRunsMillis());
>         assertEquals(Boolean.valueOf(blockWhenExhausted),
>                 Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
>         assertEquals(Boolean.valueOf(lifo),
> Boolean.valueOf(dummyPool.getLifo()));
>         dummyPool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testWhenExhaustedFail() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(false);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumIdle());
>         pool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlock() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(10L);
>         String obj1 = pool.borrowObject();
>         assertNotNull(obj1);
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>         pool.returnObject(obj1);
>         pool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockInterupt() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         String obj1 = pool.borrowObject();
>
>         // Make sure on object was obtained
>         assertNotNull(obj1);
>
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>         wtt.interrupt();
>
>         // Give interupt time to take effect
>         Thread.sleep(200);
>
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>
>         // Return object to the pool
>         pool.returnObject(obj1);
>
>         // Bug POOL-162 - check there is now an object in the pool
>         pool.setMaxWaitMillis(10L);
>         String obj2 = null;
>         try {
>              obj2 = pool.borrowObject();
>             assertNotNull(obj2);
>         } catch(NoSuchElementException e) {
>             // Not expected
>             fail("NoSuchElementException not expected");
>         }
>         pool.returnObject(obj2);
>         pool.close();
>
>     }
>
>     @Test(timeout=60000)
>     public void testEvictWhileEmpty() throws Exception {
>         pool.evict();
>         pool.evict();
>         pool.close();
>     }
>
>     /**
>      * Tests addObject contention between ensureMinIdle triggered by
>      * the Evictor with minIdle > 0 and borrowObject.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictAddObjects() throws Exception {
>         factory.setMakeLatency(300);
>         factory.setMaxTotal(2);
>         pool.setMaxTotal(2);
>         pool.setMinIdle(1);
>         pool.borrowObject(); // numActive = 1, numIdle = 0
>         // Create a test thread that will run once and try a borrow after
>         // 150ms fixed delay
>         TestThread borrower = new TestThread(pool, 1, 150, false);
>         Thread borrowerThread = new Thread(borrower);
>         // Set evictor to run in 100 ms - will create idle instance
>         pool.setTimeBetweenEvictionRunsMillis(100);
>         borrowerThread.start();  // Off to the races
>         borrowerThread.join();
>         assertTrue(!borrower.failed());
>     }
>
>     @Test(timeout=60000)
>     public void testEvictLIFO() throws Exception {
>         checkEvict(true);
>     }
>
>     @Test(timeout=60000)
>     public void testEvictFIFO() throws Exception {
>         checkEvict(false);
>     }
>
>     private void checkEvict(boolean lifo) throws Exception {
>         // yea this is hairy but it tests all the code paths in GOP.evict()
>         pool.setSoftMinEvictableIdleTimeMillis(10);
>         pool.setMinIdle(2);
>         pool.setTestWhileIdle(true);
>         pool.setLifo(lifo);
>         PoolUtils.prefill(pool, 5);
>         pool.evict();
>         factory.setEvenValid(false);
>         factory.setOddValid(false);
>         factory.setThrowExceptionOnActivate(true);
>         pool.evict();
>         PoolUtils.prefill(pool, 5);
>         factory.setThrowExceptionOnActivate(false);
>         factory.setThrowExceptionOnPassivate(true);
>         pool.evict();
>         factory.setThrowExceptionOnPassivate(false);
>         factory.setEvenValid(true);
>         factory.setOddValid(true);
>         Thread.sleep(125);
>         pool.evict();
>         assertEquals(2, pool.getNumIdle());
>     }
>
>     /**
>      * Test to make sure evictor visits least recently used objects first,
>      * regardless of FIFO/LIFO.
>      *
>      * JIRA: POOL-86
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testEvictionOrder() throws Exception {
>         checkEvictionOrder(false);
>         tearDown();
>         setUp();
>         checkEvictionOrder(true);
>     }
>
>     private void checkEvictionOrder(boolean lifo) throws Exception {
>         checkEvictionOrderPart1(lifo);
>         tearDown();
>         setUp();
>         checkEvictionOrderPart2(lifo);
>     }
>
>     private void checkEvictionOrderPart1(boolean lifo) throws Exception {
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         // Order, oldest to youngest, is "0", "1", ...,"4"
>         pool.evict(); // Should evict "0" and "1"
>         Object obj = pool.borrowObject();
>         assertTrue("oldest not evicted", !obj.equals("0"));
>         assertTrue("second oldest not evicted", !obj.equals("1"));
>         // 2 should be next out for FIFO, 4 for LIFO
>         assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
>     }
>
>     private void checkEvictionOrderPart2(boolean lifo) throws Exception {
>         // Two eviction runs in sequence
>         pool.setNumTestsPerEvictionRun(2);
>         pool.setMinEvictableIdleTimeMillis(100);
>         pool.setLifo(lifo);
>         for (int i = 0; i < 5; i++) {
>             pool.addObject();
>             Thread.sleep(100);
>         }
>         pool.evict(); // Should evict "0" and "1"
>         pool.evict(); // Should evict "2" and "3"
>         Object obj = pool.borrowObject();
>         assertEquals("Wrong instance remaining in pool", "4", obj);
>     }
>
>     /**
>      * Verifies that the evictor visits objects in expected order
>      * and frequency.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testEvictorVisiting() throws Exception {
>         checkEvictorVisiting(true);
>         checkEvictorVisiting(false);
>     }
>
>     private void checkEvictorVisiting(boolean lifo) throws Exception {
>         VisitTrackerFactory<Object> trackerFactory = new
> VisitTrackerFactory<Object>();
>         GenericObjectPool<VisitTracker<Object>> trackerPool =
>                 new
> GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(2);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // Visit oldest 2 - 0 and 1
>         VisitTracker<Object> obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         //  borrow, return, borrow, return
>         //  FIFO will move 0 and 1 to end
>         //  LIFO, 7 out, then in, then out, then in
>         trackerPool.evict();  // Should visit 2 and 3 in either case
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() >= 4) {
>                 assertEquals("Unexpected instance visited " +
> tracker.getId(),
>                         0, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
>
>         trackerFactory = new VisitTrackerFactory<Object>();
>         trackerPool = new
> GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>         trackerPool.setNumTestsPerEvictionRun(3);
>         trackerPool.setMinEvictableIdleTimeMillis(-1);
>         trackerPool.setTestWhileIdle(true);
>         trackerPool.setLifo(lifo);
>         trackerPool.setTestOnReturn(false);
>         trackerPool.setTestOnBorrow(false);
>         for (int i = 0; i < 8; i++) {
>             trackerPool.addObject();
>         }
>         trackerPool.evict(); // 0, 1, 2
>         trackerPool.evict(); // 3, 4, 5
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         obj = trackerPool.borrowObject();
>         trackerPool.returnObject(obj);
>         // borrow, return, borrow, return
>         //  FIFO 3,4,5,6,7,0,1,2
>         //  LIFO 7,6,5,4,3,2,1,0
>         // In either case, pointer should be at 6
>         trackerPool.evict();
>         // Should hit 6,7,0 - 0 for second time
>         for (int i = 0; i < 8; i++) {
>             VisitTracker<Object> tracker = trackerPool.borrowObject();
>             if (tracker.getId() != 0) {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         1, tracker.getValidateCount());
>             } else {
>                 assertEquals("Instance " +  tracker.getId() +
>                         " visited wrong number of times.",
>                         2, tracker.getValidateCount());
>             }
>         }
>         trackerPool.close();
>
>         // Randomly generate a pools with random numTests
>         // and make sure evictor cycles through elements appropriately
>         int[] smallPrimes = {2, 3, 5, 7};
>         Random random = new Random();
>         random.setSeed(System.currentTimeMillis());
>         for (int i = 0; i < 4; i++) {
>             for (int j = 0; j < 5; j++) {
>                 trackerPool = new
> GenericObjectPool<VisitTracker<Object>>(trackerFactory);
>                 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
>                 trackerPool.setMinEvictableIdleTimeMillis(-1);
>                 trackerPool.setTestWhileIdle(true);
>                 trackerPool.setLifo(lifo);
>                 trackerPool.setTestOnReturn(false);
>                 trackerPool.setTestOnBorrow(false);
>                 trackerPool.setMaxIdle(-1);
>                 int instanceCount = 10 + random.nextInt(20);
>                 trackerPool.setMaxTotal(instanceCount);
>                 for (int k = 0; k < instanceCount; k++) {
>                     trackerPool.addObject();
>                 }
>
>                 // Execute a random number of evictor runs
>                 int runs = 10 + random.nextInt(50);
>                 for (int k = 0; k < runs; k++) {
>                     trackerPool.evict();
>                 }
>
>                 // Number of times evictor should have cycled through the
> pool
>                 int cycleCount = (runs *
> trackerPool.getNumTestsPerEvictionRun()) /
>                         instanceCount;
>
>                 // Look at elements and make sure they are visited
> cycleCount
>                 // or cycleCount + 1 times
>                 VisitTracker<Object> tracker = null;
>                 int visitCount = 0;
>                 for (int k = 0; k < instanceCount; k++) {
>                     tracker = trackerPool.borrowObject();
>                     assertTrue(trackerPool.getNumActive() <=
> trackerPool.getMaxTotal());
>                     visitCount = tracker.getValidateCount();
>                     assertTrue(visitCount >= cycleCount &&
>                             visitCount <= cycleCount + 1);
>                 }
>                 trackerPool.close();
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnPassivateDuringReturn() throws Exception {
>         String obj = pool.borrowObject();
>         factory.setThrowExceptionOnPassivate(true);
>         pool.returnObject(obj);
>         assertEquals(0,pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringBorrow() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnBorrow(true);
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail on next borrow
> attempt
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnDestroyDuringReturn() throws Exception {
>         factory.setThrowExceptionOnDestroy(true);
>         pool.setTestOnReturn(true);
>         String obj1 = pool.borrowObject();
>         pool.borrowObject();
>         factory.setValid(false); // Make validation fail
>         pool.returnObject(obj1);
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testExceptionOnActivateDuringBorrow() throws Exception {
>         String obj1 = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         pool.returnObject(obj1);
>         pool.returnObject(obj2);
>         factory.setThrowExceptionOnActivate(true);
>         factory.setEvenValid(false);
>         // Activation will now throw every other time
>         // First attempt throws, but loop continues and second succeeds
>         String obj = pool.borrowObject();
>         assertEquals(1, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>
>         pool.returnObject(obj);
>         factory.setValid(false);
>         // Validation will now fail on activation when borrowObject returns
>         // an idle instance, and then when attempting to create a new
> instance
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         assertEquals(0, pool.getNumActive());
>         assertEquals(0, pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testNegativeMaxTotal() throws Exception {
>         pool.setMaxTotal(-1);
>         pool.setBlockWhenExhausted(false);
>         String obj = pool.borrowObject();
>         assertEquals(getNthObject(0),obj);
>         pool.returnObject(obj);
>     }
>
>     @Test(timeout=60000)
>     public void testMaxIdle() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(8);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMaxIdleZero() throws Exception {
>         pool.setMaxTotal(100);
>         pool.setMaxIdle(0);
>         String[] active = new String[100];
>         for(int i=0;i<100;i++) {
>             active[i] = pool.borrowObject();
>         }
>         assertEquals(100,pool.getNumActive());
>         assertEquals(0,pool.getNumIdle());
>         for(int i=0;i<100;i++) {
>             pool.returnObject(active[i]);
>             assertEquals(99 - i,pool.getNumActive());
>             assertEquals(0, pool.getNumIdle());
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMaxTotal() throws Exception {
>         pool.setMaxTotal(3);
>         pool.setBlockWhenExhausted(false);
>
>         pool.borrowObject();
>         pool.borrowObject();
>         pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testTimeoutNoLeak() throws Exception {
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(10);
>         pool.setBlockWhenExhausted(true);
>         String obj = pool.borrowObject();
>         String obj2 = pool.borrowObject();
>         try {
>             pool.borrowObject();
>             fail("Expecting NoSuchElementException");
>         } catch (NoSuchElementException ex) {
>             // expected
>         }
>         pool.returnObject(obj2);
>         pool.returnObject(obj);
>
>         pool.borrowObject();
>         pool.borrowObject();
>     }
>
>     @Test(timeout=60000)
>     public void testMaxTotalZero() throws Exception {
>         pool.setMaxTotal(0);
>         pool.setBlockWhenExhausted(false);
>
>         try {
>             pool.borrowObject();
>             fail("Expected NoSuchElementException");
>         } catch(NoSuchElementException e) {
>             // expected
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMaxTotalUnderLoad() {
>         // Config
>         int numThreads = 199; // And main thread makes a round 200.
>         int numIter = 20;
>         int delay = 25;
>         int maxTotal = 10;
>
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
>
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             // Factor of 2 on iterations so main thread does work whilst
> other
>             // threads are running. Factor of 2 on delay so average delay
> for
>             // other threads == actual delay for main thread
>             threads[i] = new TestThread(pool, numIter * 2, delay * 2);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         // Give the threads a chance to start doing some work
>         try {
>             Thread.sleep(5000);
>         } catch(InterruptedException e) {
>             // ignored
>         }
>
>         for (int i = 0; i < numIter; i++) {
>             String obj = null;
>             try {
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 obj = pool.borrowObject();
>                 // Under load, observed _numActive > _maxTotal
>                 if (pool.getNumActive() > pool.getMaxTotal()) {
>                     throw new IllegalStateException("Too many active
> objects");
>                 }
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             } catch (Exception e) {
>                 // Shouldn't happen
>                 e.printStackTrace();
>                 fail("Exception on borrow");
>             } finally {
>                 if (obj != null) {
>                     try {
>                         pool.returnObject(obj);
>                     } catch (Exception e) {
>                         // Ignore
>                     }
>                 }
>             }
>         }
>
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testSettersAndGetters() throws Exception {
>         {
>             // The object receives an Exception during its creation to
> prevent
>             // memory leaks. See BaseGenericObjectPool constructor for
> more details.
>             assertTrue(false == "".equals(pool.getCreationStackTrace()));
>         }
>         {
>             assertEquals(0, pool.getBorrowedCount());
>         }
>         {
>             assertEquals(0, pool.getReturnedCount());
>         }
>         {
>             assertEquals(0, pool.getCreatedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByEvictorCount());
>         }
>         {
>             assertEquals(0, pool.getDestroyedByBorrowValidationCount());
>         }
>         {
>             assertEquals(0, pool.getMeanActiveTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanIdleTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
>         }
>         {
>             assertEquals(0, pool.getNumIdle());
>         }
>         {
>             pool.setMaxTotal(123);
>             assertEquals(123,pool.getMaxTotal());
>         }
>         {
>             pool.setMaxIdle(12);
>             assertEquals(12,pool.getMaxIdle());
>         }
>         {
>             pool.setMaxWaitMillis(1234L);
>             assertEquals(1234L,pool.getMaxWaitMillis());
>         }
>         {
>             pool.setMinEvictableIdleTimeMillis(12345L);
>             assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setNumTestsPerEvictionRun(11);
>             assertEquals(11,pool.getNumTestsPerEvictionRun());
>         }
>         {
>             pool.setTestOnBorrow(true);
>             assertTrue(pool.getTestOnBorrow());
>             pool.setTestOnBorrow(false);
>             assertTrue(!pool.getTestOnBorrow());
>         }
>         {
>             pool.setTestOnReturn(true);
>             assertTrue(pool.getTestOnReturn());
>             pool.setTestOnReturn(false);
>             assertTrue(!pool.getTestOnReturn());
>         }
>         {
>             pool.setTestWhileIdle(true);
>             assertTrue(pool.getTestWhileIdle());
>             pool.setTestWhileIdle(false);
>             assertTrue(!pool.getTestWhileIdle());
>         }
>         {
>             pool.setTimeBetweenEvictionRunsMillis(11235L);
>             assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
>         }
>         {
>             pool.setSoftMinEvictableIdleTimeMillis(12135L);
>             assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
>         }
>         {
>             pool.setBlockWhenExhausted(true);
>             assertTrue(pool.getBlockWhenExhausted());
>             pool.setBlockWhenExhausted(false);
>             assertFalse(pool.getBlockWhenExhausted());
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testDefaultConfiguration() throws Exception {
>         assertConfiguration(new GenericObjectPoolConfig(),pool);
>     }
>
>     @Test(timeout=60000)
>     public void testSetConfig() throws Exception {
>         GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
>         assertConfiguration(expected,pool);
>         expected.setMaxTotal(2);
>         expected.setMaxIdle(3);
>         expected.setMaxWaitMillis(5L);
>         expected.setMinEvictableIdleTimeMillis(7L);
>         expected.setNumTestsPerEvictionRun(9);
>         expected.setTestOnCreate(true);
>         expected.setTestOnBorrow(true);
>         expected.setTestOnReturn(true);
>         expected.setTestWhileIdle(true);
>         expected.setTimeBetweenEvictionRunsMillis(11L);
>         expected.setBlockWhenExhausted(false);
>         pool.setConfig(expected);
>         assertConfiguration(expected,pool);
>     }
>
>     @Test(timeout=60000)
>     public void testStartAndStopEvictor() throws Exception {
>         // set up pool without evictor
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(6);
>         pool.setMinEvictableIdleTimeMillis(100L);
>
>         for(int j=0;j<2;j++) {
>             // populate the pool
>             {
>                 String[] active = new String[6];
>                 for(int i=0;i<6;i++) {
>                     active[i] = pool.borrowObject();
>                 }
>                 for(int i=0;i<6;i++) {
>                     pool.returnObject(active[i]);
>                 }
>             }
>
>             // note that it stays populated
>             assertEquals("Should have 6 idle",6,pool.getNumIdle());
>
>             // start the evictor
>             pool.setTimeBetweenEvictionRunsMillis(50L);
>
>             // wait a second (well, .2 seconds)
>             try { Thread.sleep(200L); } catch(InterruptedException e) { }
>
>             // assert that the evictor has cleared out the pool
>             assertEquals("Should have 0 idle",0,pool.getNumIdle());
>
>             // stop the evictor
>             pool.startEvictor(0L);
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testEvictionWithNegativeNumTests() throws Exception {
>         // when numTestsPerEvictionRun is negative, it represents a
> fraction of the idle objects to test
>         pool.setMaxIdle(6);
>         pool.setMaxTotal(6);
>         pool.setNumTestsPerEvictionRun(-2);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>
>         String[] active = new String[6];
>         for(int i=0;i<6;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<6;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 6 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() <= 6);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should at most 3 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() <= 3);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertTrue("Should be at most 2 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() <= 2);
>         try { Thread.sleep(100L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " +
> pool.getNumIdle(),0,pool.getNumIdle());
>     }
>
>     @Test(timeout=60000)
>     public void testEviction() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(100);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
>
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " +
> pool.getNumIdle(),0,pool.getNumIdle());
>
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 500 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 500);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 400 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 400);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 300 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 300);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 200 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 200);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertTrue("Should be less than 100 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() < 100);
>         try { Thread.sleep(600L); } catch(InterruptedException e) { }
>         assertEquals("Should be zero idle, found " +
> pool.getNumIdle(),0,pool.getNumIdle());
>     }
>
>     public static class TestEvictionPolicy<T> implements EvictionPolicy<T>
> {
>
>         private AtomicInteger callCount = new AtomicInteger(0);
>
>         @Override
>         public boolean evict(EvictionConfig config, PooledObject<T>
> underTest,
>                 int idleCount) {
>             if (callCount.incrementAndGet() > 1500) {
>                 return true;
>             } else {
>                 return false;
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testEvictionPolicy() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMaxTotal(500);
>         pool.setNumTestsPerEvictionRun(500);
>         pool.setMinEvictableIdleTimeMillis(250L);
>         pool.setTimeBetweenEvictionRunsMillis(500L);
>         pool.setTestWhileIdle(true);
>
>         // ClassNotFoundException
>         try {
>
> pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
>             fail("setEvictionPolicyClassName must throw an error if the
> class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
>
>         // InstantiationException
>         try {
>
> pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the
> class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
>
>         // IllegalAccessException
>         try {
>
> pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
>             fail("setEvictionPolicyClassName must throw an error if the
> class name is invalid.");
>         } catch (IllegalArgumentException e) {
>             // expected
>         }
>
>
> pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
>         assertEquals(TestEvictionPolicy.class.getName(),
> pool.getEvictionPolicyClassName());
>
>         String[] active = new String[500];
>         for(int i=0;i<500;i++) {
>             active[i] = pool.borrowObject();
>         }
>         for(int i=0;i<500;i++) {
>             pool.returnObject(active[i]);
>         }
>
>         // Eviction policy ignores first 1500 attempts to evict and then
> always
>         // evicts. After 1s, there should have been two runs of 500 tests
> so no
>         // evictions
>         try { Thread.sleep(1000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 500 idle", 500, pool.getNumIdle());
>         // A further 1s wasn't enough so allow 2s for the evictor to clear
> out
>         // all of the idle objects.
>         try { Thread.sleep(2000L); } catch(InterruptedException e) { }
>         assertEquals("Should be 0 idle", 0, pool.getNumIdle());
>     }
>
>
>     @Test(timeout=60000)
>     public void testEvictionSoftMinIdle() throws Exception {
>         class TimeTest extends BasePooledObjectFactory<TimeTest> {
>             private final long createTime;
>             public TimeTest() {
>                 createTime = System.currentTimeMillis();
>             }
>             @Override
>             public TimeTest create() throws Exception {
>                 return new TimeTest();
>             }
>             @Override
>             public PooledObject<TimeTest> wrap(TimeTest value) {
>                 return new DefaultPooledObject<TimeTest>(value);
>             }
>             public long getCreateTime() {
>                 return createTime;
>             }
>         }
>
>         GenericObjectPool<TimeTest> timePool =
>             new GenericObjectPool<TimeTest>(new TimeTest());
>
>         timePool.setMaxIdle(5);
>         timePool.setMaxTotal(5);
>         timePool.setNumTestsPerEvictionRun(5);
>         timePool.setMinEvictableIdleTimeMillis(3000L);
>         timePool.setSoftMinEvictableIdleTimeMillis(1000L);
>         timePool.setMinIdle(2);
>
>         TimeTest[] active = new TimeTest[5];
>         Long[] creationTime = new Long[5] ;
>         for(int i=0;i<5;i++) {
>             active[i] = timePool.borrowObject();
>             creationTime[i] = Long.valueOf((active[i]).getCreateTime());
>         }
>
>         for(int i=0;i<5;i++) {
>             timePool.returnObject(active[i]);
>         }
>
>         // Soft evict all but minIdle(2)
>         Thread.sleep(1500L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 2,
> timePool.getNumIdle());
>
>         // Hard evict the rest.
>         Thread.sleep(2000L);
>         timePool.evict();
>         assertEquals("Idle count different than expected.", 0,
> timePool.getNumIdle());
>         timePool.close();
>     }
>
>     @Test(timeout=60000)
>     public void testEvictionInvalid() throws Exception {
>
>         final GenericObjectPool<Object> invalidFactoryPool =
>                 new GenericObjectPool<Object>(new InvalidFactory());
>
>         invalidFactoryPool.setMaxIdle(1);
>         invalidFactoryPool.setMaxTotal(1);
>         invalidFactoryPool.setTestOnBorrow(false);
>         invalidFactoryPool.setTestOnReturn(false);
>         invalidFactoryPool.setTestWhileIdle(true);
>         invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
>         invalidFactoryPool.setNumTestsPerEvictionRun(1);
>
>         Object p = invalidFactoryPool.borrowObject();
>         invalidFactoryPool.returnObject(p);
>
>         // Run eviction in a separate thread
>         Thread t = new EvictionThread<Object>(invalidFactoryPool);
>         t.start();
>
>         // Sleep to make sure evictor has started
>         Thread.sleep(300);
>
>         try {
>             invalidFactoryPool.borrowObject(1);
>         } catch (NoSuchElementException nsee) {
>             // Ignore
>         }
>
>         // Make sure evictor has finished
>         Thread.sleep(1000);
>
>         // Should have an empty pool
>         assertEquals("Idle count different than expected.", 0,
> invalidFactoryPool.getNumIdle());
>         assertEquals("Total count different than expected.", 0,
> invalidFactoryPool.getNumActive());
>         invalidFactoryPool.close();
>     }
>
>     /**
>      * POOL-231 - verify that concurrent invalidates of the same object do
> not
>      * corrupt pool destroyCount.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testConcurrentInvalidate() throws Exception {
>         // Get allObjects and idleObjects loaded with some instances
>         final int nObjects = 1000;
>         pool.setMaxTotal(nObjects);
>         pool.setMaxIdle(nObjects);
>         final String[] obj = new String[nObjects];
>         for (int i = 0; i < nObjects; i++) {
>             obj[i] = pool.borrowObject();
>         }
>         for (int i = 0; i < nObjects; i++) {
>             if (i % 2 == 0) {
>                 pool.returnObject(obj[i]);
>             }
>         }
>         final int nThreads = 20;
>         final int nIterations = 60;
>         final InvalidateThread[] threads = new InvalidateThread[nThreads];
>         // Randomly generated list of distinct invalidation targets
>         final ArrayList<Integer> targets = new ArrayList<Integer>();
>         final Random random = new Random();
>         for (int j = 0; j < nIterations; j++) {
>             // Get a random invalidation target
>             Integer targ = Integer.valueOf(random.nextInt(nObjects));
>             while (targets.contains(targ)) {
>                 targ = Integer.valueOf(random.nextInt(nObjects));
>             }
>             targets.add(targ);
>             // Launch nThreads threads all trying to invalidate the target
>             for (int i = 0; i < nThreads; i++) {
>                 threads[i] = new InvalidateThread(pool,
> obj[targ.intValue()]);
>             }
>             for (int i = 0; i < nThreads; i++) {
>                 new Thread(threads[i]).start();
>             }
>             boolean done = false;
>             while (!done) {
>                 done = true;
>                 for (int i = 0; i < nThreads; i++) {
>                     done = done && threads[i].complete();
>                 }
>                 Thread.sleep(100);
>             }
>         }
>         Assert.assertEquals(nIterations, pool.getDestroyedCount());
>     }
>
>     /**
>      * Attempts to invalidate an object, swallowing IllegalStateException.
>      */
>     static class InvalidateThread implements Runnable {
>         private final String obj;
>         private final ObjectPool<String> pool;
>         private boolean done = false;
>         public InvalidateThread(ObjectPool<String> pool, String obj) {
>             this.obj = obj;
>             this.pool = pool;
>         }
>         @Override
>         public void run() {
>             try {
>                 pool.invalidateObject(obj);
>             } catch (IllegalStateException ex) {
>                 // Ignore
>             } catch (Exception ex) {
>                 Assert.fail("Unexpected exception " + ex.toString());
>             } finally {
>                 done = true;
>             }
>         }
>         public boolean complete() {
>             return done;
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testMinIdle() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         String[] active = new String[5];
>         active[0] = pool.borrowObject();
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=1 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
>
>     @Test(timeout=60000)
>     public void testMinIdleMaxTotal() throws Exception {
>         pool.setMaxIdle(500);
>         pool.setMinIdle(5);
>         pool.setMaxTotal(10);
>         pool.setNumTestsPerEvictionRun(0);
>         pool.setMinEvictableIdleTimeMillis(50L);
>         pool.setTimeBetweenEvictionRunsMillis(100L);
>         pool.setTestWhileIdle(true);
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         String[] active = new String[10];
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=0 ; i<5 ; i++) {
>             active[i] = pool.borrowObject();
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 5 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 5);
>
>         for(int i=0 ; i<5 ; i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 10);
>
>         for(int i=0 ; i<10 ; i++) {
>             active[i] = pool.borrowObject();
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 0 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 0);
>
>         for(int i=0 ; i<10 ; i++) {
>             pool.returnObject(active[i]);
>         }
>
>         try { Thread.sleep(150L); } catch(InterruptedException e) { }
>         assertTrue("Should be 10 idle, found " +
> pool.getNumIdle(),pool.getNumIdle() == 10);
>     }
>
>     /**
>      * Kicks off <numThreads> test threads, each of which will go through
>      * <iterations> borrow-return cycles with random delay times <= delay
>      * in between.
>      */
>     private void runTestThreads(int numThreads, int iterations, int delay)
> {
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool,iterations,delay);
>             Thread t = new Thread(threads[i]);
>             t.start();
>         }
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testThreaded1() throws Exception {
>         pool.setMaxTotal(15);
>         pool.setMaxIdle(15);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(20, 100, 50);
>     }
>
>     /**
>      * Verifies that maxTotal is not exceeded when factory destroyObject
>      * has high latency, testOnReturn is set and there is high incidence of
>      * validation failures.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMaxTotalInvariant() throws Exception {
>         int maxTotal = 15;
>         factory.setEvenValid(false);     // Every other validation fails
>         factory.setDestroyLatency(100);  // Destroy takes 100 ms
>         factory.setMaxTotal(maxTotal); // (makes - destroys) bound
>         factory.setValidationEnabled(true);
>         pool.setMaxTotal(maxTotal);
>         pool.setMaxIdle(-1);
>         pool.setTestOnReturn(true);
>         pool.setMaxWaitMillis(1000L);
>         runTestThreads(5, 10, 50);
>     }
>
>     @Test(timeout=60000)
>     public void testConcurrentBorrowAndEvict() throws Exception {
>
>         pool.setMaxTotal(1);
>         pool.addObject();
>
>         for( int i=0; i<5000; i++) {
>             ConcurrentBorrowAndEvictThread one =
>                     new ConcurrentBorrowAndEvictThread(true);
>             ConcurrentBorrowAndEvictThread two =
>                     new ConcurrentBorrowAndEvictThread(false);
>
>             one.start();
>             two.start();
>             one.join();
>             two.join();
>
>             pool.returnObject(one.obj);
>
>             /* Uncomment this for a progress indication
>             if (i % 10 == 0) {
>                 System.out.println(i/10);
>             }
>             */
>         }
>     }
>
>     /**
>      * POOL-189
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testWhenExhaustedBlockClosePool() throws Exception {
>         pool.setMaxTotal(1);
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(-1);
>         Object obj1 = pool.borrowObject();
>
>         // Make sure an object was obtained
>         assertNotNull(obj1);
>
>         // Create a separate thread to try and borrow another object
>         WaitingTestThread wtt = new WaitingTestThread(pool, 200);
>         wtt.start();
>         // Give wtt time to start
>         Thread.sleep(200);
>
>         // close the pool (Bug POOL-189)
>         pool.close();
>
>         // Give interrupt time to take effect
>         Thread.sleep(200);
>
>         // Check thread was interrupted
>         assertTrue(wtt._thrown instanceof InterruptedException);
>     }
>
>     private class ConcurrentBorrowAndEvictThread extends Thread {
>         private boolean borrow;
>         public String obj;
>
>         public ConcurrentBorrowAndEvictThread(boolean borrow) {
>             this.borrow = borrow;
>         }
>
>         @Override
>         public void run() {
>             try {
>                 if (borrow) {
>                     obj = pool.borrowObject();
>                 } else {
>                     pool.evict();
>                 }
>             } catch (Exception e) { /* Ignore */}
>         }
>     }
>
>     static class TestThread implements Runnable {
>         private final java.util.Random _random = new java.util.Random();
>
>         // Thread config items
>         private final ObjectPool<String> _pool;
>         private final int _iter;
>         private final int _delay;
>         private final boolean _randomDelay;
>         private final Object _expectedObject;
>
>         private volatile boolean _complete = false;
>         private volatile boolean _failed = false;
>         private volatile Throwable _error;
>
>         public TestThread(ObjectPool<String> pool) {
>             this(pool, 100, 50, true, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter) {
>             this(pool, iter, 50, true, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter, int delay) {
>             this(pool, iter, delay, true, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay) {
>             this(pool, iter, delay, randomDelay, null);
>         }
>
>         public TestThread(ObjectPool<String> pool, int iter, int delay,
>                 boolean randomDelay, Object obj) {
>             _pool = pool;
>             _iter = iter;
>             _delay = delay;
>             _randomDelay = randomDelay;
>             _expectedObject = obj;
>         }
>
>         public boolean complete() {
>             return _complete;
>         }
>
>         public boolean failed() {
>             return _failed;
>         }
>
>         @Override
>         public void run() {
>             for(int i=0;i<_iter;i++) {
>                 long delay =
>                     _randomDelay ? (long)_random.nextInt(_delay) : _delay;
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 String obj = null;
>                 try {
>                     obj = _pool.borrowObject();
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>
>                 if (_expectedObject != null &&
> !_expectedObject.equals(obj)) {
>                     _error = new Throwable("Expected: "+_expectedObject+ "
> found: "+obj);
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>
>                 try {
>                     Thread.sleep(delay);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>                 try {
>                     _pool.returnObject(obj);
>                 } catch(Exception e) {
>                     _error = e;
>                     _failed = true;
>                     _complete = true;
>                     break;
>                 }
>             }
>             _complete = true;
>         }
>     }
>
>     @Test(timeout=60000)
>     public void testFIFO() throws Exception {
>         String o = null;
>         pool.setLifo(false);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Oldest", "0", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Youngest", "2", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
>
>     @Test(timeout=60000)
>     public void testLIFO() throws Exception {
>         String o = null;
>         pool.setLifo(true);
>         pool.addObject(); // "0"
>         pool.addObject(); // "1"
>         pool.addObject(); // "2"
>         assertEquals("Youngest", "2", pool.borrowObject());
>         assertEquals("Middle", "1", pool.borrowObject());
>         assertEquals("Oldest", "0", pool.borrowObject());
>         o = pool.borrowObject();
>         assertEquals("new-3", "3", o);
>         pool.returnObject(o);
>         assertEquals("returned-3", o, pool.borrowObject());
>         assertEquals("new-4", "4", pool.borrowObject());
>     }
>
>     @Test(timeout=60000)
>     public void testAddObject() throws Exception {
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         pool.addObject();
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>         String obj = pool.borrowObject();
>         assertEquals("should be zero idle", 0, pool.getNumIdle());
>         assertEquals("should be one active", 1, pool.getNumActive());
>         pool.returnObject(obj);
>         assertEquals("should be one idle", 1, pool.getNumIdle());
>         assertEquals("should be zero active", 0, pool.getNumActive());
>     }
>
>     protected GenericObjectPool<String> pool = null;
>
>     private SimpleFactory factory = null;
>
>     private void assertConfiguration(GenericObjectPoolConfig expected,
> GenericObjectPool<?> actual) throws Exception {
>
> assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
>                 Boolean.valueOf(actual.getTestOnCreate()));
>
> assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
>                 Boolean.valueOf(actual.getTestOnBorrow()));
>
> assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
>                 Boolean.valueOf(actual.getTestOnReturn()));
>
> assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
>                 Boolean.valueOf(actual.getTestWhileIdle()));
>         assertEquals("whenExhaustedAction",
>                 Boolean.valueOf(expected.getBlockWhenExhausted()),
>                 Boolean.valueOf(actual.getBlockWhenExhausted()));
>
> assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
>         assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
>
> assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
>
> assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
>
> assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
>
> assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
>     }
>
>     public static class SimpleFactory implements
> PooledObjectFactory<String> {
>         public SimpleFactory() {
>             this(true);
>         }
>         public SimpleFactory(boolean valid) {
>             this(valid,valid);
>         }
>         public SimpleFactory(boolean evalid, boolean ovalid) {
>             evenValid = evalid;
>             oddValid = ovalid;
>         }
>         public synchronized void setValid(boolean valid) {
>             setEvenValid(valid);
>             setOddValid(valid);
>         }
>         public synchronized void setEvenValid(boolean valid) {
>             evenValid = valid;
>         }
>         public synchronized void setOddValid(boolean valid) {
>             oddValid = valid;
>         }
>         public synchronized void setThrowExceptionOnPassivate(boolean
> bool) {
>             exceptionOnPassivate = bool;
>         }
>         public synchronized void setMaxTotal(int maxTotal) {
>             this.maxTotal = maxTotal;
>         }
>         public synchronized void setDestroyLatency(long destroyLatency) {
>             this.destroyLatency = destroyLatency;
>         }
>         public synchronized void setMakeLatency(long makeLatency) {
>             this.makeLatency = makeLatency;
>         }
>         public synchronized void setValidateLatency(long validateLatency) {
>             this.validateLatency = validateLatency;
>         }
>         @Override
>         public PooledObject<String> makeObject() {
>             final long waitLatency;
>             synchronized(this) {
>                 activeCount++;
>                 if (activeCount > maxTotal) {
>                     throw new IllegalStateException(
>                         "Too many active instances: " + activeCount);
>                 }
>                 waitLatency = makeLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             final int counter;
>             synchronized(this) {
>                 counter = makeCounter++;
>             }
>             return new
> DefaultPooledObject<String>(String.valueOf(counter));
>         }
>         @Override
>         public void destroyObject(PooledObject<String> obj) throws
> Exception {
>             final long waitLatency;
>             final boolean hurl;
>             synchronized(this) {
>                 waitLatency = destroyLatency;
>                 hurl = exceptionOnDestroy;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             synchronized(this) {
>                 activeCount--;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         @Override
>         public boolean validateObject(PooledObject<String> obj) {
>             final boolean validate;
>             final boolean evenTest;
>             final boolean oddTest;
>             final long waitLatency;
>             final int counter;
>             synchronized(this) {
>                 validate = enableValidation;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>                 waitLatency = validateLatency;
>             }
>             if (waitLatency > 0) {
>                 doWait(waitLatency);
>             }
>             if (validate) {
>                 return counter%2 == 0 ? evenTest : oddTest;
>             }
>             else {
>                 return true;
>             }
>         }
>         @Override
>         public void activateObject(PooledObject<String> obj) throws
> Exception {
>             final boolean hurl;
>             final boolean evenTest;
>             final boolean oddTest;
>             final int counter;
>             synchronized(this) {
>                 hurl = exceptionOnActivate;
>                 evenTest = evenValid;
>                 oddTest = oddValid;
>                 counter = validateCounter++;
>             }
>             if (hurl) {
>                 if (!(counter%2 == 0 ? evenTest : oddTest)) {
>                     throw new Exception();
>                 }
>             }
>         }
>         @Override
>         public void passivateObject(PooledObject<String> obj) throws
> Exception {
>             final boolean hurl;
>             synchronized(this) {
>                 hurl = exceptionOnPassivate;
>             }
>             if (hurl) {
>                 throw new Exception();
>             }
>         }
>         int makeCounter = 0;
>         int validateCounter = 0;
>         int activeCount = 0;
>         boolean evenValid = true;
>         boolean oddValid = true;
>         boolean exceptionOnPassivate = false;
>         boolean exceptionOnActivate = false;
>         boolean exceptionOnDestroy = false;
>         boolean enableValidation = true;
>         long destroyLatency = 0;
>         long makeLatency = 0;
>         long validateLatency = 0;
>         int maxTotal = Integer.MAX_VALUE;
>
>         public synchronized boolean isThrowExceptionOnActivate() {
>             return exceptionOnActivate;
>         }
>
>         public synchronized void setThrowExceptionOnActivate(boolean b) {
>             exceptionOnActivate = b;
>         }
>
>         public synchronized void setThrowExceptionOnDestroy(boolean b) {
>             exceptionOnDestroy = b;
>         }
>
>         public synchronized boolean isValidationEnabled() {
>             return enableValidation;
>         }
>
>         public synchronized void setValidationEnabled(boolean b) {
>             enableValidation = b;
>         }
>
>         public synchronized int getMakeCounter() {
>             return makeCounter;
>         }
>
>         private void doWait(long latency) {
>             try {
>                 Thread.sleep(latency);
>             } catch (InterruptedException ex) {
>                 // ignore
>             }
>         }
>     }
>     @Override
>     protected boolean isLifo() {
>         return true;
>     }
>
>     @Override
>     protected boolean isFifo() {
>         return false;
>     }
>
>     /*
>      * Note: This test relies on timing for correct execution. There
> *should* be
>      * enough margin for this to work correctly on most (all?) systems but
> be
>      * aware of this if you see a failure of this test.
>      */
>     @Test(timeout=60000)
>     public void testBorrowObjectFairness() {
>
>         // Config
>         int numThreads = 30;
>         int maxTotal = 10;
>
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTimeBetweenEvictionRunsMillis(-1);
>
>         // Start threads to borrow objects
>         TestThread[] threads = new TestThread[numThreads];
>         for(int i=0;i<numThreads;i++) {
>             threads[i] = new TestThread(pool, 1, 2000, false,
> String.valueOf(i % maxTotal));
>             Thread t = new Thread(threads[i]);
>             t.start();
>             // Short delay to ensure threads start in correct order
>             try {
>                 Thread.sleep(50);
>             } catch (InterruptedException e) {
>                 fail(e.toString());
>             }
>         }
>
>         // Wait for threads to finish
>         for(int i=0;i<numThreads;i++) {
>             while(!(threads[i]).complete()) {
>                 try {
>                     Thread.sleep(500L);
>                 } catch(InterruptedException e) {
>                     // ignored
>                 }
>             }
>             if(threads[i].failed()) {
>                 fail("Thread "+i+" failed: "+threads[i]._error.toString());
>             }
>         }
>     }
>
>     /**
>      * On first borrow, first object fails validation, second object is OK.
>      * Subsequent borrows are OK. This was POOL-152.
>      */
>     @Test(timeout=60000)
>     public void testBrokenFactoryShouldNotBlockPool() {
>         int maxTotal = 1;
>
>         factory.setMaxTotal(maxTotal);
>         pool.setMaxTotal(maxTotal);
>         pool.setBlockWhenExhausted(true);
>         pool.setTestOnBorrow(true);
>
>         // First borrow object will need to create a new object which will
> fail
>         // validation.
>         String obj = null;
>         Exception ex = null;
>         factory.setValid(false);
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e) {
>             ex = e;
>         }
>         // Failure expected
>         assertNotNull(ex);
>         assertTrue(ex instanceof NoSuchElementException);
>         assertNull(obj);
>
>         // Configure factory to create valid objects so subsequent borrows
> work
>         factory.setValid(true);
>
>         // Subsequent borrows should be OK
>         try {
>             obj = pool.borrowObject();
>         } catch (Exception e1) {
>             fail();
>         }
>         assertNotNull(obj);
>         try {
>             pool.returnObject(obj);
>         } catch (Exception e) {
>             fail();
>         }
>     }
>
>     /*
>      * Very simple test thread that just tries to borrow an object from
>      * the provided pool returns it after a wait
>      */
>     static class WaitingTestThread extends Thread {
>         private final GenericObjectPool<String> _pool;
>         private final long _pause;
>         private Throwable _thrown;
>
>         private long preborrow; // just before borrow
>         private long postborrow; //  borrow returned
>         private long postreturn; // after object was returned
>         private long ended;
>         private String objectId;
>
>         public WaitingTestThread(GenericObjectPool<String> pool, long
> pause) {
>             _pool = pool;
>             _pause = pause;
>             _thrown = null;
>         }
>
>         @Override
>         public void run() {
>             try {
>                 preborrow = System.currentTimeMillis();
>                 String obj = _pool.borrowObject();
>                 objectId = obj;
>                 postborrow = System.currentTimeMillis();
>                 Thread.sleep(_pause);
>                 _pool.returnObject(obj);
>                 postreturn = System.currentTimeMillis();
>             } catch (Exception e) {
>                 _thrown = e;
>             } finally{
>                 ended = System.currentTimeMillis();
>             }
>         }
>     }
>
>     private static final boolean DISPLAY_THREAD_DETAILS=
>
> Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details",
> "false")).booleanValue();
>     // To pass this to a Maven test, use:
>     // mvn test
> -DargLine="-DTestGenericObjectPool.display.thread.details=true"
>     // @see http://jira.codehaus.org/browse/SUREFIRE-121
>
>     /*
>      * Test multi-threaded pool access.
>      * Multiple threads, but maxTotal only allows half the threads to
> succeed.
>      *
>      * This test was prompted by Continuum build failures in the Commons
> DBCP test case:
>      * TestPerUserPoolDataSource.testMultipleThreads2()
>      * Let's see if the this fails on Continuum too!
>      */
>     @Test(timeout=60000)
>     public void testMaxWaitMultiThreaded() throws Exception {
>         final long maxWait = 500; // wait for connection
>         final long holdTime = 2 * maxWait; // how long to hold connection
>         final int threads = 10; // number of threads to grab the object
> initially
>         pool.setBlockWhenExhausted(true);
>         pool.setMaxWaitMillis(maxWait);
>         pool.setMaxTotal(threads);
>         // Create enough threads so half the threads will have to wait
>         WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
>         for(int i=0; i < wtt.length; i++){
>             wtt[i] = new WaitingTestThread(pool,holdTime);
>         }
>         long origin = System.currentTimeMillis()-1000;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].start();
>         }
>         int failed = 0;
>         for(int i=0; i < wtt.length; i++){
>             wtt[i].join();
>             if (wtt[i]._thrown != null){
>                 failed++;
>             }
>         }
>         if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
>             System.out.println(
>                     "MaxWait: " + maxWait +
>                     " HoldTime: " + holdTime +
>                      " MaxTotal: " + threads +
>                     " Threads: " + wtt.length +
>                     " Failed: " + failed
>                     );
>             for(int i=0; i < wtt.length; i++){
>                 WaitingTestThread wt = wtt[i];
>                 System.out.println(
>                         "Preborrow: " + (wt.preborrow-origin) +
>                         " Postborrow: " + (wt.postborrow != 0 ?
> wt.postborrow-origin : -1) +
>                         " BorrowTime: " + (wt.postborrow != 0 ?
> wt.postborrow-wt.preborrow : -1) +
>                         " PostReturn: " + (wt.postreturn != 0 ?
> wt.postreturn-origin : -1) +
>                         " Ended: " + (wt.ended-origin) +
>                         " ObjId: " + wt.objectId
>                         );
>             }
>         }
>         assertEquals("Expected half the threads to
> fail",wtt.length/2,failed);
>     }
>
>     /**
>      * Test the following scenario:
>      *   Thread 1 borrows an instance
>      *   Thread 2 starts to borrow another instance before thread 1
> returns its instance
>      *   Thread 1 returns its instance while thread 2 is validating its
> newly created instance
>      * The test verifies that the instance created by Thread 2 is not
> leaked.
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test(timeout=60000)
>     public void testMakeConcurrentWithReturn() throws Exception {
>         pool.setTestOnBorrow(true);
>         factory.setValid(true);
>         // Borrow and return an instance, with a short wait
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
>         thread1.start();
>         Thread.sleep(50); // wait for validation to succeed
>         // Slow down validation and borrow an instance
>         factory.setValidateLatency(400);
>         String instance = pool.borrowObject();
>         // Now make sure that we have not leaked an instance
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
>         pool.returnObject(instance);
>         assertEquals(factory.getMakeCounter(), pool.getNumIdle());
>     }
>
>     /**
>      * Ensure the pool is registered.
>      */
>     @Test(timeout=60000)
>     public void testJmxRegistration() {
>         ObjectName oname = pool.getJmxName();
>         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
>         Set<ObjectName> result = mbs.queryNames(oname, null);
>         Assert.assertEquals(1, result.size());
>         pool.jmxUnregister();
>
>         GenericObjectPoolConfig config = new GenericObjectPoolConfig();
>         config.setJmxEnabled(false);
>         GenericObjectPool<String> poolWithoutJmx = new
> GenericObjectPool<String>(factory, config);
>         assertNull(poolWithoutJmx.getJmxName());
>         config.setJmxEnabled(true);
>         poolWithoutJmx.jmxUnregister();
>
>         config.setJmxNameBase(null);
>         GenericObjectPool<String> poolWithDefaultJmxNameBase = new
> GenericObjectPool<String>(factory, config);
>         assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
>     }
>
>     /**
>      * Verify that threads waiting on a depleted pool get served when a
> checked out object is
>      * invalidated.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testInvalidateFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         GenericObjectPool<String> pool = new
> GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(500);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance
>         String obj = pool.borrowObject();
>         // Launch another thread - will block, but fail in 500 ms
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
>         thread2.start();
>         // Invalidate the object borrowed by this thread - should allow
> thread2 to create
>         Thread.sleep(20);
>         pool.invalidateObject(obj);
>         Thread.sleep(600); // Wait for thread2 to timeout
>         if (thread2._thrown != null) {
>             fail(thread2._thrown.toString());
>         }
>     }
>
>     /**
>      * Verify that threads waiting on a depleted pool get served when a
> returning object fails
>      * validation.
>      *
>      * JIRA: POOL-240
>      *
>      * @throws Exception May occur in some failure modes
>      */
>     @Test
>     public void testValidationFailureOnReturnFreesCapacity()
>         throws Exception {
>         SimpleFactory factory = new SimpleFactory();
>         factory.setValid(false); // Validate will always fail
>         factory.setValidationEnabled(true);
>         GenericObjectPool<String> pool = new
> GenericObjectPool<String>(factory);
>         pool.setMaxTotal(2);
>         pool.setMaxWaitMillis(1500);
>         pool.setTestOnReturn(true);
>         pool.setTestOnBorrow(false);
>         // Borrow an instance and hold if for 5 seconds
>         WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
>         thread1.start();
>         // Borrow another instance and return it after 500 ms (validation
> will fail)
>         WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
>         thread2.start();
>         Thread.sleep(50);
>         // Try to borrow an object
>         String obj = pool.borrowObject();
>         pool.returnObject(obj);
>     }
>
>     @Test
>     public void testSwallowedExceptionListener() {
>         pool.setSwallowedExceptionListener(null); // must simply return
>         final List<Exception> swallowedExceptions = new
> ArrayList<Exception>();
>         /*
>          * A simple listener, that will throw a OOM on 3rd exception.
>          */
>         final SwallowedExceptionListener listener = new
> SwallowedExceptionListener() {
>             @Override
>             public void onSwallowException(Exception e) {
>                 if (swallowedExceptions.size() == 2) {
>                     throw new OutOfMemoryError();
>                 } else {
>                     swallowedExceptions.add(e);
>                 }
>             }
>         };
>         pool.setSwallowedExceptionListener(listener);
>
>         Exception e1 = new Exception();
>         Exception e2 = new ArrayIndexOutOfBoundsException();
>
>         pool.swallowException(e1);
>         pool.swallowException(e2);
>
>         try {
>             pool.swallowException(e1);
>             fail("Not supposed to get here");
>         } catch (OutOfMemoryError oom) {
>             // expected
>         }
>
>         assertEquals(2, swallowedExceptions.size());
>     }
>
>     // POOL-248
>     @Test(expected=IllegalStateException.class)
>     public void testMultipleReturnOfSameObject() throws Exception {
>         final GenericObjectPool<String> pool = new
> GenericObjectPool<String>(
>                 factory, new GenericObjectPoolConfig());
>
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
>
>         String obj = pool.borrowObject();
>
>         Assert.assertEquals(1, pool.getNumActive());
>         Assert.assertEquals(0, pool.getNumIdle());
>
>         pool.returnObject(obj);
>
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>
>         pool.returnObject(obj);
>
>         Assert.assertEquals(0, pool.getNumActive());
>         Assert.assertEquals(1, pool.getNumIdle());
>     }
>
>     private static final class DummyFactory
>             extends BasePooledObjectFactory<Object> {
>         @Override
>         public Object create() throws Exception {
>             return null;
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>     }
>
>
>     private static class InvalidFactory
>             extends BasePooledObjectFactory<Object> {
>
>         @Override
>         public Object create() throws Exception {
>             return new Object();
>         }
>         @Override
>         public PooledObject<Object> wrap(Object value) {
>             return new DefaultPooledObject<Object>(value);
>         }
>
>         @Override
>         public boolean validateObject(PooledObject<Object> obj) {
>             try {
>                 Thread.sleep(1000);
>             } catch (InterruptedException e) {
>                 // Ignore
>             }
>             return false;
>         }
>     }
>
>     private static class EvictionThread<T> extends Thread {
>
>         private final GenericObjectPool<T> pool;
>
>         public EvictionThread(GenericObjectPool<T> pool) {
>             this.pool = pool;
>         }
>
>         @Override
>         public void run() {
>             try {
>                 pool.evict();
>             } catch (Exception e) {
>                 // Ignore
>             }
>         }
>     }
> }
>
> Not sure of the meaning you are inferring with 'multiplexed'
>
> Best of Luck in Brasil
> Martin
> ______________________________________________
>  _____ _          _____             _          _____     ___ _
>            _____               _     _   _
> |_   _| |_ ___   |  _  |___ ___ ___| |_ ___   |   __|___|  _| |_ _ _ _ ___
> ___ ___   |   __|___ _ _ ___ _| |___| |_|_|___ ___
>   | | |   | -_|  |     | . | .'|  _|   | -_|  |__   | . |  _|  _| | | |
> .'|  _| -_|  |   __| . | | |   | . | .'|  _| | . |   |
>   |_| |_|_|___|  |__|__|  _|__,|___|_|_|___|  |_____|___|_| |_|
> |_____|__,|_| |___|  |__|  |___|___|_|_|___|__,|_| |_|___|_|_|
>                        |_|
>
>
> From: JLeskovar@telecomsys.com
> To: user@commons.apache.org
> Subject: Multiplexed connections in commons pool
> Date: Wed, 18 Jun 2014 23:07:44 +0000
>
>
>
>
>
>
>
>
>
> Hi there,
>
> I have an application that needs to perform connection pooling, with the
> proviso that it's okay - and actually preferable - for more than one client
> to checkout and use the same connection object from the pool. Ideally, I
> would also like
>  to limit the number of concurrent clients that are using a single
> connection object. I'm wondering what the best way to do this is. As a
> quick and dirty option, I suppose I could basically have my
> PooledObjectFactory return the same objects from makeObject(),
>  and manually keep track of objects from inside my implementation.
> Thoughts?
>
> Cheers,
> James Leskovar
>
> Software Engineer, Location Platforms
> TeleCommunication Systems, Inc.
>
>
>
> [ Address : TCS, iC Enterprise 1, Innovation Campus, Squires Way, Nth
> Wollongong, NSW, 2500, Australia ]
>
> [ Tel : +61 2 4221 2940 ] [ Fax : +61 2 4221 2901 ]
>
> [ Email : James.Leskovar@telecomsys.com ]
>
>
>
> CONFIDENTIALITY NOTICE: The information contained in this message may be
> privileged and/or confidential. If you are not the intended recipient, or
> responsible for delivering this message to the intended recipient, any
> review, forwarding, dissemination, distribution or copying of this
> communication or any attachment(s) is strictly prohibited. If you have
> received this message in error, please notify the sender immediately, and
> delete it and all attachments from your computer and network.
>




-- 
E-Mail: garydgregory@gmail.com | ggregory@apache.org
Java Persistence with Hibernate, Second Edition
<http://www.manning.com/bauer3/>
JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
Spring Batch in Action <http://www.manning.com/templier/>
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory

RE: Multiplexed connections in commons pool

Posted by Martin Gainty <mg...@hotmail.com>.
James-
There is a nice test-case in 2.2 apache-commons that covers (Max-timeout-per-connection) and max-connections you are seeking:
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.pool2.impl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.SwallowedExceptionListener;
import org.apache.commons.pool2.TestBaseObjectPool;
import org.apache.commons.pool2.VisitTracker;
import org.apache.commons.pool2.VisitTrackerFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @version $Revision: 1569016 $
 */
public class TestGenericObjectPool extends TestBaseObjectPool {

    @Override
    protected ObjectPool<String> makeEmptyPool(int mincap) {
       GenericObjectPool<String> mtPool =
               new GenericObjectPool<String>(new SimpleFactory());
       mtPool.setMaxTotal(mincap);
       mtPool.setMaxIdle(mincap);
       return mtPool;
    }

    @Override
    protected ObjectPool<Object> makeEmptyPool(
            final PooledObjectFactory<Object> fac) {
        return new GenericObjectPool<Object>(fac);
    }

    @Override
    protected Object getNthObject(int n) {
        return String.valueOf(n);
    }

    @Before
    public void setUp() throws Exception {
        factory = new SimpleFactory();
        pool = new GenericObjectPool<String>(factory);
    }

    @After
    public void tearDown() throws Exception {
        String poolName = pool.getJmxName().toString();
        pool.clear();
        pool.close();
        pool = null;
        factory = null;

        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(new ObjectName(
                "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
        // There should be no registered pools at this point
        int registeredPoolCount = result.size();
        StringBuilder msg = new StringBuilder("Current pool is: ");
        msg.append(poolName);
        msg.append("  Still open pools are: ");
        for (ObjectName name : result) {
            // Clean these up ready for the next test
            msg.append(name.toString());
            msg.append(" created via\n");
            msg.append(mbs.getAttribute(name, "CreationStackTrace"));
            msg.append('\n');
            mbs.unregisterMBean(name);
        }
        Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
    }

    @Test(expected=IllegalArgumentException.class)
    public void testConstructorNullFactory() {
        // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
        assertNotNull(new GenericObjectPool<String>(null));
        // TODO this currently causes tearDown to report an error
        // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
    }

    @Test(timeout=60000)
    public void testConstructors() throws Exception {

        // Make constructor arguments all different from defaults
        int minIdle = 2;
        long maxWait = 3;
        int maxIdle = 4;
        int maxTotal = 5;
        long minEvictableIdleTimeMillis = 6;
        int numTestsPerEvictionRun = 7;
        boolean testOnBorrow = true;
        boolean testOnReturn = true;
        boolean testWhileIdle = true;
        long timeBetweenEvictionRunsMillis = 8;
        boolean blockWhenExhausted = false;
        boolean lifo = false;
        PooledObjectFactory<Object> dummyFactory = new DummyFactory();
        GenericObjectPool<Object> dummyPool =
                new GenericObjectPool<Object>(dummyFactory);
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
                Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();

        GenericObjectPoolConfig config =
                new GenericObjectPoolConfig();
        config.setLifo(lifo);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWait);
        config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setTestWhileIdle(testWhileIdle);
        config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        config.setBlockWhenExhausted(blockWhenExhausted);
        dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
        assertEquals(maxIdle, dummyPool.getMaxIdle());
        assertEquals(maxWait, dummyPool.getMaxWaitMillis());
        assertEquals(minIdle, dummyPool.getMinIdle());
        assertEquals(maxTotal, dummyPool.getMaxTotal());
        assertEquals(minEvictableIdleTimeMillis,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(testOnBorrow),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(testOnReturn),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(testWhileIdle),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(timeBetweenEvictionRunsMillis,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(blockWhenExhausted),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedFail() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(false);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumIdle());
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlock() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(10L);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlockInterupt() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        String obj1 = pool.borrowObject();

        // Make sure on object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);
        wtt.interrupt();

        // Give interupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);

        // Return object to the pool
        pool.returnObject(obj1);

        // Bug POOL-162 - check there is now an object in the pool
        pool.setMaxWaitMillis(10L);
        String obj2 = null;
        try {
             obj2 = pool.borrowObject();
            assertNotNull(obj2);
        } catch(NoSuchElementException e) {
            // Not expected
            fail("NoSuchElementException not expected");
        }
        pool.returnObject(obj2);
        pool.close();

    }

    @Test(timeout=60000)
    public void testEvictWhileEmpty() throws Exception {
        pool.evict();
        pool.evict();
        pool.close();
    }

    /**
     * Tests addObject contention between ensureMinIdle triggered by
     * the Evictor with minIdle &gt; 0 and borrowObject.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictAddObjects() throws Exception {
        factory.setMakeLatency(300);
        factory.setMaxTotal(2);
        pool.setMaxTotal(2);
        pool.setMinIdle(1);
        pool.borrowObject(); // numActive = 1, numIdle = 0
        // Create a test thread that will run once and try a borrow after
        // 150ms fixed delay
        TestThread borrower = new TestThread(pool, 1, 150, false);
        Thread borrowerThread = new Thread(borrower);
        // Set evictor to run in 100 ms - will create idle instance
        pool.setTimeBetweenEvictionRunsMillis(100);
        borrowerThread.start();  // Off to the races
        borrowerThread.join();
        assertTrue(!borrower.failed());
    }

    @Test(timeout=60000)
    public void testEvictLIFO() throws Exception {
        checkEvict(true);
    }

    @Test(timeout=60000)
    public void testEvictFIFO() throws Exception {
        checkEvict(false);
    }

    private void checkEvict(boolean lifo) throws Exception {
        // yea this is hairy but it tests all the code paths in GOP.evict()
        pool.setSoftMinEvictableIdleTimeMillis(10);
        pool.setMinIdle(2);
        pool.setTestWhileIdle(true);
        pool.setLifo(lifo);
        PoolUtils.prefill(pool, 5);
        pool.evict();
        factory.setEvenValid(false);
        factory.setOddValid(false);
        factory.setThrowExceptionOnActivate(true);
        pool.evict();
        PoolUtils.prefill(pool, 5);
        factory.setThrowExceptionOnActivate(false);
        factory.setThrowExceptionOnPassivate(true);
        pool.evict();
        factory.setThrowExceptionOnPassivate(false);
        factory.setEvenValid(true);
        factory.setOddValid(true);
        Thread.sleep(125);
        pool.evict();
        assertEquals(2, pool.getNumIdle());
    }

    /**
     * Test to make sure evictor visits least recently used objects first,
     * regardless of FIFO/LIFO.
     *
     * JIRA: POOL-86
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictionOrder() throws Exception {
        checkEvictionOrder(false);
        tearDown();
        setUp();
        checkEvictionOrder(true);
    }

    private void checkEvictionOrder(boolean lifo) throws Exception {
        checkEvictionOrderPart1(lifo);
        tearDown();
        setUp();
        checkEvictionOrderPart2(lifo);
    }

    private void checkEvictionOrderPart1(boolean lifo) throws Exception {
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        // Order, oldest to youngest, is "0", "1", ...,"4"
        pool.evict(); // Should evict "0" and "1"
        Object obj = pool.borrowObject();
        assertTrue("oldest not evicted", !obj.equals("0"));
        assertTrue("second oldest not evicted", !obj.equals("1"));
        // 2 should be next out for FIFO, 4 for LIFO
        assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
    }

    private void checkEvictionOrderPart2(boolean lifo) throws Exception {
        // Two eviction runs in sequence
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        pool.evict(); // Should evict "0" and "1"
        pool.evict(); // Should evict "2" and "3"
        Object obj = pool.borrowObject();
        assertEquals("Wrong instance remaining in pool", "4", obj);
    }

    /**
     * Verifies that the evictor visits objects in expected order
     * and frequency.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testEvictorVisiting() throws Exception {
        checkEvictorVisiting(true);
        checkEvictorVisiting(false);
    }

    private void checkEvictorVisiting(boolean lifo) throws Exception {
        VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
        GenericObjectPool<VisitTracker<Object>> trackerPool =
                new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(2);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // Visit oldest 2 - 0 and 1
        VisitTracker<Object> obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        //  borrow, return, borrow, return
        //  FIFO will move 0 and 1 to end
        //  LIFO, 7 out, then in, then out, then in
        trackerPool.evict();  // Should visit 2 and 3 in either case
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() >= 4) {
                assertEquals("Unexpected instance visited " + tracker.getId(),
                        0, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        trackerFactory = new VisitTrackerFactory<Object>();
        trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(3);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // 0, 1, 2
        trackerPool.evict(); // 3, 4, 5
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        // borrow, return, borrow, return
        //  FIFO 3,4,5,6,7,0,1,2
        //  LIFO 7,6,5,4,3,2,1,0
        // In either case, pointer should be at 6
        trackerPool.evict();
        // Should hit 6,7,0 - 0 for second time
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() != 0) {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        2, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        // Randomly generate a pools with random numTests
        // and make sure evictor cycles through elements appropriately
        int[] smallPrimes = {2, 3, 5, 7};
        Random random = new Random();
        random.setSeed(System.currentTimeMillis());
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 5; j++) {
                trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
                trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
                trackerPool.setMinEvictableIdleTimeMillis(-1);
                trackerPool.setTestWhileIdle(true);
                trackerPool.setLifo(lifo);
                trackerPool.setTestOnReturn(false);
                trackerPool.setTestOnBorrow(false);
                trackerPool.setMaxIdle(-1);
                int instanceCount = 10 + random.nextInt(20);
                trackerPool.setMaxTotal(instanceCount);
                for (int k = 0; k < instanceCount; k++) {
                    trackerPool.addObject();
                }

                // Execute a random number of evictor runs
                int runs = 10 + random.nextInt(50);
                for (int k = 0; k < runs; k++) {
                    trackerPool.evict();
                }

                // Number of times evictor should have cycled through the pool
                int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
                        instanceCount;

                // Look at elements and make sure they are visited cycleCount
                // or cycleCount + 1 times
                VisitTracker<Object> tracker = null;
                int visitCount = 0;
                for (int k = 0; k < instanceCount; k++) {
                    tracker = trackerPool.borrowObject();
                    assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
                    visitCount = tracker.getValidateCount();
                    assertTrue(visitCount >= cycleCount &&
                            visitCount <= cycleCount + 1);
                }
                trackerPool.close();
            }
        }
    }

    @Test(timeout=60000)
    public void testExceptionOnPassivateDuringReturn() throws Exception {
        String obj = pool.borrowObject();
        factory.setThrowExceptionOnPassivate(true);
        pool.returnObject(obj);
        assertEquals(0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringBorrow() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnBorrow(true);
        pool.borrowObject();
        factory.setValid(false); // Make validation fail on next borrow attempt
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringReturn() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnReturn(true);
        String obj1 = pool.borrowObject();
        pool.borrowObject();
        factory.setValid(false); // Make validation fail
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnActivateDuringBorrow() throws Exception {
        String obj1 = pool.borrowObject();
        String obj2 = pool.borrowObject();
        pool.returnObject(obj1);
        pool.returnObject(obj2);
        factory.setThrowExceptionOnActivate(true);
        factory.setEvenValid(false);
        // Activation will now throw every other time
        // First attempt throws, but loop continues and second succeeds
        String obj = pool.borrowObject();
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);
        factory.setValid(false);
        // Validation will now fail on activation when borrowObject returns
        // an idle instance, and then when attempting to create a new instance
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(0, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testNegativeMaxTotal() throws Exception {
        pool.setMaxTotal(-1);
        pool.setBlockWhenExhausted(false);
        String obj = pool.borrowObject();
        assertEquals(getNthObject(0),obj);
        pool.returnObject(obj);
    }

    @Test(timeout=60000)
    public void testMaxIdle() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(8);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxIdleZero() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(0);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals(0, pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxTotal() throws Exception {
        pool.setMaxTotal(3);
        pool.setBlockWhenExhausted(false);

        pool.borrowObject();
        pool.borrowObject();
        pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testTimeoutNoLeak() throws Exception {
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(10);
        pool.setBlockWhenExhausted(true);
        String obj = pool.borrowObject();
        String obj2 = pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        pool.returnObject(obj2);
        pool.returnObject(obj);

        pool.borrowObject();
        pool.borrowObject();
    }

    @Test(timeout=60000)
    public void testMaxTotalZero() throws Exception {
        pool.setMaxTotal(0);
        pool.setBlockWhenExhausted(false);

        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testMaxTotalUnderLoad() {
        // Config
        int numThreads = 199; // And main thread makes a round 200.
        int numIter = 20;
        int delay = 25;
        int maxTotal = 10;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            // Factor of 2 on iterations so main thread does work whilst other
            // threads are running. Factor of 2 on delay so average delay for
            // other threads == actual delay for main thread
            threads[i] = new TestThread(pool, numIter * 2, delay * 2);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        // Give the threads a chance to start doing some work
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) {
            // ignored
        }

        for (int i = 0; i < numIter; i++) {
            String obj = null;
            try {
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                obj = pool.borrowObject();
                // Under load, observed _numActive > _maxTotal
                if (pool.getNumActive() > pool.getMaxTotal()) {
                    throw new IllegalStateException("Too many active objects");
                }
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
            } catch (Exception e) {
                // Shouldn't happen
                e.printStackTrace();
                fail("Exception on borrow");
            } finally {
                if (obj != null) {
                    try {
                        pool.returnObject(obj);
                    } catch (Exception e) {
                        // Ignore
                    }
                }
            }
        }

        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testSettersAndGetters() throws Exception {
        {
            // The object receives an Exception during its creation to prevent
            // memory leaks. See BaseGenericObjectPool constructor for more details.
            assertTrue(false == "".equals(pool.getCreationStackTrace()));
        }
        {
            assertEquals(0, pool.getBorrowedCount());
        }
        {
            assertEquals(0, pool.getReturnedCount());
        }
        {
            assertEquals(0, pool.getCreatedCount());
        }
        {
            assertEquals(0, pool.getDestroyedCount());
        }
        {
            assertEquals(0, pool.getDestroyedByEvictorCount());
        }
        {
            assertEquals(0, pool.getDestroyedByBorrowValidationCount());
        }
        {
            assertEquals(0, pool.getMeanActiveTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanIdleTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getNumIdle());
        }
        {
            pool.setMaxTotal(123);
            assertEquals(123,pool.getMaxTotal());
        }
        {
            pool.setMaxIdle(12);
            assertEquals(12,pool.getMaxIdle());
        }
        {
            pool.setMaxWaitMillis(1234L);
            assertEquals(1234L,pool.getMaxWaitMillis());
        }
        {
            pool.setMinEvictableIdleTimeMillis(12345L);
            assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
        }
        {
            pool.setNumTestsPerEvictionRun(11);
            assertEquals(11,pool.getNumTestsPerEvictionRun());
        }
        {
            pool.setTestOnBorrow(true);
            assertTrue(pool.getTestOnBorrow());
            pool.setTestOnBorrow(false);
            assertTrue(!pool.getTestOnBorrow());
        }
        {
            pool.setTestOnReturn(true);
            assertTrue(pool.getTestOnReturn());
            pool.setTestOnReturn(false);
            assertTrue(!pool.getTestOnReturn());
        }
        {
            pool.setTestWhileIdle(true);
            assertTrue(pool.getTestWhileIdle());
            pool.setTestWhileIdle(false);
            assertTrue(!pool.getTestWhileIdle());
        }
        {
            pool.setTimeBetweenEvictionRunsMillis(11235L);
            assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
        }
        {
            pool.setSoftMinEvictableIdleTimeMillis(12135L);
            assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
        }
        {
            pool.setBlockWhenExhausted(true);
            assertTrue(pool.getBlockWhenExhausted());
            pool.setBlockWhenExhausted(false);
            assertFalse(pool.getBlockWhenExhausted());
        }
    }

    @Test(timeout=60000)
    public void testDefaultConfiguration() throws Exception {
        assertConfiguration(new GenericObjectPoolConfig(),pool);
    }

    @Test(timeout=60000)
    public void testSetConfig() throws Exception {
        GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
        assertConfiguration(expected,pool);
        expected.setMaxTotal(2);
        expected.setMaxIdle(3);
        expected.setMaxWaitMillis(5L);
        expected.setMinEvictableIdleTimeMillis(7L);
        expected.setNumTestsPerEvictionRun(9);
        expected.setTestOnCreate(true);
        expected.setTestOnBorrow(true);
        expected.setTestOnReturn(true);
        expected.setTestWhileIdle(true);
        expected.setTimeBetweenEvictionRunsMillis(11L);
        expected.setBlockWhenExhausted(false);
        pool.setConfig(expected);
        assertConfiguration(expected,pool);
    }

    @Test(timeout=60000)
    public void testStartAndStopEvictor() throws Exception {
        // set up pool without evictor
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(6);
        pool.setMinEvictableIdleTimeMillis(100L);

        for(int j=0;j<2;j++) {
            // populate the pool
            {
                String[] active = new String[6];
                for(int i=0;i<6;i++) {
                    active[i] = pool.borrowObject();
                }
                for(int i=0;i<6;i++) {
                    pool.returnObject(active[i]);
                }
            }

            // note that it stays populated
            assertEquals("Should have 6 idle",6,pool.getNumIdle());

            // start the evictor
            pool.setTimeBetweenEvictionRunsMillis(50L);

            // wait a second (well, .2 seconds)
            try { Thread.sleep(200L); } catch(InterruptedException e) { }

            // assert that the evictor has cleared out the pool
            assertEquals("Should have 0 idle",0,pool.getNumIdle());

            // stop the evictor
            pool.startEvictor(0L);
        }
    }

    @Test(timeout=60000)
    public void testEvictionWithNegativeNumTests() throws Exception {
        // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(-2);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);

        String[] active = new String[6];
        for(int i=0;i<6;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<6;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testEviction() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(100);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());

        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {

        private AtomicInteger callCount = new AtomicInteger(0);

        @Override
        public boolean evict(EvictionConfig config, PooledObject<T> underTest,
                int idleCount) {
            if (callCount.incrementAndGet() > 1500) {
                return true;
            } else {
                return false;
            }
        }
    }

    @Test(timeout=60000)
    public void testEvictionPolicy() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(500);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        // ClassNotFoundException
        try {
            pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // InstantiationException
        try {
            pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // IllegalAccessException
        try {
            pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
        assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        // Eviction policy ignores first 1500 attempts to evict and then always
        // evicts. After 1s, there should have been two runs of 500 tests so no
        // evictions
        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertEquals("Should be 500 idle", 500, pool.getNumIdle());
        // A further 1s wasn't enough so allow 2s for the evictor to clear out
        // all of the idle objects.
        try { Thread.sleep(2000L); } catch(InterruptedException e) { }
        assertEquals("Should be 0 idle", 0, pool.getNumIdle());
    }


    @Test(timeout=60000)
    public void testEvictionSoftMinIdle() throws Exception {
        class TimeTest extends BasePooledObjectFactory<TimeTest> {
            private final long createTime;
            public TimeTest() {
                createTime = System.currentTimeMillis();
            }
            @Override
            public TimeTest create() throws Exception {
                return new TimeTest();
            }
            @Override
            public PooledObject<TimeTest> wrap(TimeTest value) {
                return new DefaultPooledObject<TimeTest>(value);
            }
            public long getCreateTime() {
                return createTime;
            }
        }

        GenericObjectPool<TimeTest> timePool =
            new GenericObjectPool<TimeTest>(new TimeTest());

        timePool.setMaxIdle(5);
        timePool.setMaxTotal(5);
        timePool.setNumTestsPerEvictionRun(5);
        timePool.setMinEvictableIdleTimeMillis(3000L);
        timePool.setSoftMinEvictableIdleTimeMillis(1000L);
        timePool.setMinIdle(2);

        TimeTest[] active = new TimeTest[5];
        Long[] creationTime = new Long[5] ;
        for(int i=0;i<5;i++) {
            active[i] = timePool.borrowObject();
            creationTime[i] = Long.valueOf((active[i]).getCreateTime());
        }

        for(int i=0;i<5;i++) {
            timePool.returnObject(active[i]);
        }

        // Soft evict all but minIdle(2)
        Thread.sleep(1500L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());

        // Hard evict the rest.
        Thread.sleep(2000L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
        timePool.close();
    }

    @Test(timeout=60000)
    public void testEvictionInvalid() throws Exception {

        final GenericObjectPool<Object> invalidFactoryPool =
                new GenericObjectPool<Object>(new InvalidFactory());

        invalidFactoryPool.setMaxIdle(1);
        invalidFactoryPool.setMaxTotal(1);
        invalidFactoryPool.setTestOnBorrow(false);
        invalidFactoryPool.setTestOnReturn(false);
        invalidFactoryPool.setTestWhileIdle(true);
        invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
        invalidFactoryPool.setNumTestsPerEvictionRun(1);

        Object p = invalidFactoryPool.borrowObject();
        invalidFactoryPool.returnObject(p);

        // Run eviction in a separate thread
        Thread t = new EvictionThread<Object>(invalidFactoryPool);
        t.start();

        // Sleep to make sure evictor has started
        Thread.sleep(300);

        try {
            invalidFactoryPool.borrowObject(1);
        } catch (NoSuchElementException nsee) {
            // Ignore
        }

        // Make sure evictor has finished
        Thread.sleep(1000);

        // Should have an empty pool
        assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
        assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
        invalidFactoryPool.close();
    }

    /**
     * POOL-231 - verify that concurrent invalidates of the same object do not
     * corrupt pool destroyCount.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testConcurrentInvalidate() throws Exception {
        // Get allObjects and idleObjects loaded with some instances
        final int nObjects = 1000;
        pool.setMaxTotal(nObjects);
        pool.setMaxIdle(nObjects);
        final String[] obj = new String[nObjects];
        for (int i = 0; i < nObjects; i++) {
            obj[i] = pool.borrowObject();
        }
        for (int i = 0; i < nObjects; i++) {
            if (i % 2 == 0) {
                pool.returnObject(obj[i]);
            }
        }
        final int nThreads = 20;
        final int nIterations = 60;
        final InvalidateThread[] threads = new InvalidateThread[nThreads];
        // Randomly generated list of distinct invalidation targets
        final ArrayList<Integer> targets = new ArrayList<Integer>();
        final Random random = new Random();
        for (int j = 0; j < nIterations; j++) {
            // Get a random invalidation target
            Integer targ = Integer.valueOf(random.nextInt(nObjects));
            while (targets.contains(targ)) {
                targ = Integer.valueOf(random.nextInt(nObjects));
            }
            targets.add(targ);
            // Launch nThreads threads all trying to invalidate the target
            for (int i = 0; i < nThreads; i++) {
                threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
            }
            for (int i = 0; i < nThreads; i++) {
                new Thread(threads[i]).start();
            }
            boolean done = false;
            while (!done) {
                done = true;
                for (int i = 0; i < nThreads; i++) {
                    done = done && threads[i].complete();
                }
                Thread.sleep(100);
            }
        }
        Assert.assertEquals(nIterations, pool.getDestroyedCount());
    }

    /**
     * Attempts to invalidate an object, swallowing IllegalStateException.
     */
    static class InvalidateThread implements Runnable {
        private final String obj;
        private final ObjectPool<String> pool;
        private boolean done = false;
        public InvalidateThread(ObjectPool<String> pool, String obj) {
            this.obj = obj;
            this.pool = pool;
        }
        @Override
        public void run() {
            try {
                pool.invalidateObject(obj);
            } catch (IllegalStateException ex) {
                // Ignore
            } catch (Exception ex) {
                Assert.fail("Unexpected exception " + ex.toString());
            } finally {
                done = true;
            }
        }
        public boolean complete() {
            return done;
        }
    }

    @Test(timeout=60000)
    public void testMinIdle() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[5];
        active[0] = pool.borrowObject();

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=1 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    @Test(timeout=60000)
    public void testMinIdleMaxTotal() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[10];

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);

        for(int i=0 ; i<10 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);

        for(int i=0 ; i<10 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    /**
     * Kicks off <numThreads> test threads, each of which will go through
     * <iterations> borrow-return cycles with random delay times <= delay
     * in between.
     */
    private void runTestThreads(int numThreads, int iterations, int delay) {
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool,iterations,delay);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testThreaded1() throws Exception {
        pool.setMaxTotal(15);
        pool.setMaxIdle(15);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(20, 100, 50);
    }

    /**
     * Verifies that maxTotal is not exceeded when factory destroyObject
     * has high latency, testOnReturn is set and there is high incidence of
     * validation failures.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMaxTotalInvariant() throws Exception {
        int maxTotal = 15;
        factory.setEvenValid(false);     // Every other validation fails
        factory.setDestroyLatency(100);  // Destroy takes 100 ms
        factory.setMaxTotal(maxTotal); // (makes - destroys) bound
        factory.setValidationEnabled(true);
        pool.setMaxTotal(maxTotal);
        pool.setMaxIdle(-1);
        pool.setTestOnReturn(true);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(5, 10, 50);
    }

    @Test(timeout=60000)
    public void testConcurrentBorrowAndEvict() throws Exception {

        pool.setMaxTotal(1);
        pool.addObject();

        for( int i=0; i<5000; i++) {
            ConcurrentBorrowAndEvictThread one =
                    new ConcurrentBorrowAndEvictThread(true);
            ConcurrentBorrowAndEvictThread two =
                    new ConcurrentBorrowAndEvictThread(false);

            one.start();
            two.start();
            one.join();
            two.join();

            pool.returnObject(one.obj);

            /* Uncomment this for a progress indication
            if (i % 10 == 0) {
                System.out.println(i/10);
            }
            */
        }
    }

    /**
     * POOL-189
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testWhenExhaustedBlockClosePool() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        Object obj1 = pool.borrowObject();

        // Make sure an object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);

        // close the pool (Bug POOL-189)
        pool.close();

        // Give interrupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);
    }

    private class ConcurrentBorrowAndEvictThread extends Thread {
        private boolean borrow;
        public String obj;

        public ConcurrentBorrowAndEvictThread(boolean borrow) {
            this.borrow = borrow;
        }

        @Override
        public void run() {
            try {
                if (borrow) {
                    obj = pool.borrowObject();
                } else {
                    pool.evict();
                }
            } catch (Exception e) { /* Ignore */}
        }
    }

    static class TestThread implements Runnable {
        private final java.util.Random _random = new java.util.Random();

        // Thread config items
        private final ObjectPool<String> _pool;
        private final int _iter;
        private final int _delay;
        private final boolean _randomDelay;
        private final Object _expectedObject;

        private volatile boolean _complete = false;
        private volatile boolean _failed = false;
        private volatile Throwable _error;

        public TestThread(ObjectPool<String> pool) {
            this(pool, 100, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter) {
            this(pool, iter, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay) {
            this(pool, iter, delay, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay) {
            this(pool, iter, delay, randomDelay, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay, Object obj) {
            _pool = pool;
            _iter = iter;
            _delay = delay;
            _randomDelay = randomDelay;
            _expectedObject = obj;
        }

        public boolean complete() {
            return _complete;
        }

        public boolean failed() {
            return _failed;
        }

        @Override
        public void run() {
            for(int i=0;i<_iter;i++) {
                long delay =
                    _randomDelay ? (long)_random.nextInt(_delay) : _delay;
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                String obj = null;
                try {
                    obj = _pool.borrowObject();
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }

                if (_expectedObject != null && !_expectedObject.equals(obj)) {
                    _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
                    _failed = true;
                    _complete = true;
                    break;
                }

                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                try {
                    _pool.returnObject(obj);
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }
            }
            _complete = true;
        }
    }

    @Test(timeout=60000)
    public void testFIFO() throws Exception {
        String o = null;
        pool.setLifo(false);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Oldest", "0", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Youngest", "2", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testLIFO() throws Exception {
        String o = null;
        pool.setLifo(true);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Youngest", "2", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Oldest", "0", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testAddObject() throws Exception {
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        pool.addObject();
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
        String obj = pool.borrowObject();
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        assertEquals("should be one active", 1, pool.getNumActive());
        pool.returnObject(obj);
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
    }

    protected GenericObjectPool<String> pool = null;

    private SimpleFactory factory = null;

    private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
        assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
                Boolean.valueOf(actual.getTestOnCreate()));
        assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
                Boolean.valueOf(actual.getTestOnBorrow()));
        assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
                Boolean.valueOf(actual.getTestOnReturn()));
        assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
                Boolean.valueOf(actual.getTestWhileIdle()));
        assertEquals("whenExhaustedAction",
                Boolean.valueOf(expected.getBlockWhenExhausted()),
                Boolean.valueOf(actual.getBlockWhenExhausted()));
        assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
        assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
        assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
        assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
        assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
        assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
    }

    public static class SimpleFactory implements PooledObjectFactory<String> {
        public SimpleFactory() {
            this(true);
        }
        public SimpleFactory(boolean valid) {
            this(valid,valid);
        }
        public SimpleFactory(boolean evalid, boolean ovalid) {
            evenValid = evalid;
            oddValid = ovalid;
        }
        public synchronized void setValid(boolean valid) {
            setEvenValid(valid);
            setOddValid(valid);
        }
        public synchronized void setEvenValid(boolean valid) {
            evenValid = valid;
        }
        public synchronized void setOddValid(boolean valid) {
            oddValid = valid;
        }
        public synchronized void setThrowExceptionOnPassivate(boolean bool) {
            exceptionOnPassivate = bool;
        }
        public synchronized void setMaxTotal(int maxTotal) {
            this.maxTotal = maxTotal;
        }
        public synchronized void setDestroyLatency(long destroyLatency) {
            this.destroyLatency = destroyLatency;
        }
        public synchronized void setMakeLatency(long makeLatency) {
            this.makeLatency = makeLatency;
        }
        public synchronized void setValidateLatency(long validateLatency) {
            this.validateLatency = validateLatency;
        }
        @Override
        public PooledObject<String> makeObject() {
            final long waitLatency;
            synchronized(this) {
                activeCount++;
                if (activeCount > maxTotal) {
                    throw new IllegalStateException(
                        "Too many active instances: " + activeCount);
                }
                waitLatency = makeLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            final int counter;
            synchronized(this) {
                counter = makeCounter++;
            }
            return new DefaultPooledObject<String>(String.valueOf(counter));
        }
        @Override
        public void destroyObject(PooledObject<String> obj) throws Exception {
            final long waitLatency;
            final boolean hurl;
            synchronized(this) {
                waitLatency = destroyLatency;
                hurl = exceptionOnDestroy;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            synchronized(this) {
                activeCount--;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        @Override
        public boolean validateObject(PooledObject<String> obj) {
            final boolean validate;
            final boolean evenTest;
            final boolean oddTest;
            final long waitLatency;
            final int counter;
            synchronized(this) {
                validate = enableValidation;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
                waitLatency = validateLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            if (validate) {
                return counter%2 == 0 ? evenTest : oddTest;
            }
            else {
                return true;
            }
        }
        @Override
        public void activateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            final boolean evenTest;
            final boolean oddTest;
            final int counter;
            synchronized(this) {
                hurl = exceptionOnActivate;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
            }
            if (hurl) {
                if (!(counter%2 == 0 ? evenTest : oddTest)) {
                    throw new Exception();
                }
            }
        }
        @Override
        public void passivateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            synchronized(this) {
                hurl = exceptionOnPassivate;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        int makeCounter = 0;
        int validateCounter = 0;
        int activeCount = 0;
        boolean evenValid = true;
        boolean oddValid = true;
        boolean exceptionOnPassivate = false;
        boolean exceptionOnActivate = false;
        boolean exceptionOnDestroy = false;
        boolean enableValidation = true;
        long destroyLatency = 0;
        long makeLatency = 0;
        long validateLatency = 0;
        int maxTotal = Integer.MAX_VALUE;

        public synchronized boolean isThrowExceptionOnActivate() {
            return exceptionOnActivate;
        }

        public synchronized void setThrowExceptionOnActivate(boolean b) {
            exceptionOnActivate = b;
        }

        public synchronized void setThrowExceptionOnDestroy(boolean b) {
            exceptionOnDestroy = b;
        }

        public synchronized boolean isValidationEnabled() {
            return enableValidation;
        }

        public synchronized void setValidationEnabled(boolean b) {
            enableValidation = b;
        }

        public synchronized int getMakeCounter() {
            return makeCounter;
        }

        private void doWait(long latency) {
            try {
                Thread.sleep(latency);
            } catch (InterruptedException ex) {
                // ignore
            }
        }
    }
    @Override
    protected boolean isLifo() {
        return true;
    }

    @Override
    protected boolean isFifo() {
        return false;
    }

    /*
     * Note: This test relies on timing for correct execution. There *should* be
     * enough margin for this to work correctly on most (all?) systems but be
     * aware of this if you see a failure of this test.
     */
    @Test(timeout=60000)
    public void testBorrowObjectFairness() {

        // Config
        int numThreads = 30;
        int maxTotal = 10;

        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
            Thread t = new Thread(threads[i]);
            t.start();
            // Short delay to ensure threads start in correct order
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                fail(e.toString());
            }
        }

        // Wait for threads to finish
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    /**
     * On first borrow, first object fails validation, second object is OK.
     * Subsequent borrows are OK. This was POOL-152.
     */
    @Test(timeout=60000)
    public void testBrokenFactoryShouldNotBlockPool() {
        int maxTotal = 1;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTestOnBorrow(true);

        // First borrow object will need to create a new object which will fail
        // validation.
        String obj = null;
        Exception ex = null;
        factory.setValid(false);
        try {
            obj = pool.borrowObject();
        } catch (Exception e) {
            ex = e;
        }
        // Failure expected
        assertNotNull(ex);
        assertTrue(ex instanceof NoSuchElementException);
        assertNull(obj);

        // Configure factory to create valid objects so subsequent borrows work
        factory.setValid(true);

        // Subsequent borrows should be OK
        try {
            obj = pool.borrowObject();
        } catch (Exception e1) {
            fail();
        }
        assertNotNull(obj);
        try {
            pool.returnObject(obj);
        } catch (Exception e) {
            fail();
        }
    }

    /*
     * Very simple test thread that just tries to borrow an object from
     * the provided pool returns it after a wait
     */
    static class WaitingTestThread extends Thread {
        private final GenericObjectPool<String> _pool;
        private final long _pause;
        private Throwable _thrown;

        private long preborrow; // just before borrow
        private long postborrow; //  borrow returned
        private long postreturn; // after object was returned
        private long ended;
        private String objectId;

        public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
            _pool = pool;
            _pause = pause;
            _thrown = null;
        }

        @Override
        public void run() {
            try {
                preborrow = System.currentTimeMillis();
                String obj = _pool.borrowObject();
                objectId = obj;
                postborrow = System.currentTimeMillis();
                Thread.sleep(_pause);
                _pool.returnObject(obj);
                postreturn = System.currentTimeMillis();
            } catch (Exception e) {
                _thrown = e;
            } finally{
                ended = System.currentTimeMillis();
            }
        }
    }

    private static final boolean DISPLAY_THREAD_DETAILS=
        Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
    // To pass this to a Maven test, use:
    // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
    // @see http://jira.codehaus.org/browse/SUREFIRE-121

    /*
     * Test multi-threaded pool access.
     * Multiple threads, but maxTotal only allows half the threads to succeed.
     *
     * This test was prompted by Continuum build failures in the Commons DBCP test case:
     * TestPerUserPoolDataSource.testMultipleThreads2()
     * Let's see if the this fails on Continuum too!
     */
    @Test(timeout=60000)
    public void testMaxWaitMultiThreaded() throws Exception {
        final long maxWait = 500; // wait for connection
        final long holdTime = 2 * maxWait; // how long to hold connection
        final int threads = 10; // number of threads to grab the object initially
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(maxWait);
        pool.setMaxTotal(threads);
        // Create enough threads so half the threads will have to wait
        WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
        for(int i=0; i < wtt.length; i++){
            wtt[i] = new WaitingTestThread(pool,holdTime);
        }
        long origin = System.currentTimeMillis()-1000;
        for(int i=0; i < wtt.length; i++){
            wtt[i].start();
        }
        int failed = 0;
        for(int i=0; i < wtt.length; i++){
            wtt[i].join();
            if (wtt[i]._thrown != null){
                failed++;
            }
        }
        if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
            System.out.println(
                    "MaxWait: " + maxWait +
                    " HoldTime: " + holdTime +
                     " MaxTotal: " + threads +
                    " Threads: " + wtt.length +
                    " Failed: " + failed
                    );
            for(int i=0; i < wtt.length; i++){
                WaitingTestThread wt = wtt[i];
                System.out.println(
                        "Preborrow: " + (wt.preborrow-origin) +
                        " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
                        " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
                        " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
                        " Ended: " + (wt.ended-origin) +
                        " ObjId: " + wt.objectId
                        );
            }
        }
        assertEquals("Expected half the threads to fail",wtt.length/2,failed);
    }

    /**
     * Test the following scenario:
     *   Thread 1 borrows an instance
     *   Thread 2 starts to borrow another instance before thread 1 returns its instance
     *   Thread 1 returns its instance while thread 2 is validating its newly created instance
     * The test verifies that the instance created by Thread 2 is not leaked.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMakeConcurrentWithReturn() throws Exception {
        pool.setTestOnBorrow(true);
        factory.setValid(true);
        // Borrow and return an instance, with a short wait
        WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
        thread1.start();
        Thread.sleep(50); // wait for validation to succeed
        // Slow down validation and borrow an instance
        factory.setValidateLatency(400);
        String instance = pool.borrowObject();
        // Now make sure that we have not leaked an instance
        assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
        pool.returnObject(instance);
        assertEquals(factory.getMakeCounter(), pool.getNumIdle());
    }

    /**
     * Ensure the pool is registered.
     */
    @Test(timeout=60000)
    public void testJmxRegistration() {
        ObjectName oname = pool.getJmxName();
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(oname, null);
        Assert.assertEquals(1, result.size());
        pool.jmxUnregister();

        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setJmxEnabled(false);
        GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
        assertNull(poolWithoutJmx.getJmxName());
        config.setJmxEnabled(true);
        poolWithoutJmx.jmxUnregister();

        config.setJmxNameBase(null);
        GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
        assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a checked out object is
     * invalidated.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testInvalidateFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(500);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance
        String obj = pool.borrowObject();
        // Launch another thread - will block, but fail in 500 ms
        WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
        thread2.start();
        // Invalidate the object borrowed by this thread - should allow thread2 to create
        Thread.sleep(20);
        pool.invalidateObject(obj);
        Thread.sleep(600); // Wait for thread2 to timeout
        if (thread2._thrown != null) {
            fail(thread2._thrown.toString());
        }
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a returning object fails
     * validation.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testValidationFailureOnReturnFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        factory.setValid(false); // Validate will always fail
        factory.setValidationEnabled(true);
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(1500);
        pool.setTestOnReturn(true);
        pool.setTestOnBorrow(false);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance and return it after 500 ms (validation will fail)
        WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
        thread2.start();
        Thread.sleep(50);
        // Try to borrow an object
        String obj = pool.borrowObject();
        pool.returnObject(obj);
    }

    @Test
    public void testSwallowedExceptionListener() {
        pool.setSwallowedExceptionListener(null); // must simply return
        final List<Exception> swallowedExceptions = new ArrayList<Exception>();
        /*
         * A simple listener, that will throw a OOM on 3rd exception.
         */
        final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
            @Override
            public void onSwallowException(Exception e) {
                if (swallowedExceptions.size() == 2) {
                    throw new OutOfMemoryError();
                } else {
                    swallowedExceptions.add(e);
                }
            }
        };
        pool.setSwallowedExceptionListener(listener);

        Exception e1 = new Exception();
        Exception e2 = new ArrayIndexOutOfBoundsException();

        pool.swallowException(e1);
        pool.swallowException(e2);

        try {
            pool.swallowException(e1);
            fail("Not supposed to get here");
        } catch (OutOfMemoryError oom) {
            // expected
        }

        assertEquals(2, swallowedExceptions.size());
    }

    // POOL-248
    @Test(expected=IllegalStateException.class)
    public void testMultipleReturnOfSameObject() throws Exception {
        final GenericObjectPool<String> pool = new GenericObjectPool<String>(
                factory, new GenericObjectPoolConfig());

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        String obj = pool.borrowObject();

        Assert.assertEquals(1, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());
    }

    private static final class DummyFactory
            extends BasePooledObjectFactory<Object> {
        @Override
        public Object create() throws Exception {
            return null;
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }
    }


    private static class InvalidFactory
            extends BasePooledObjectFactory<Object> {

        @Override
        public Object create() throws Exception {
            return new Object();
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }

        @Override
        public boolean validateObject(PooledObject<Object> obj) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // Ignore
            }
            return false;
        }
    }

    private static class EvictionThread<T> extends Thread {

        private final GenericObjectPool<T> pool;

        public EvictionThread(GenericObjectPool<T> pool) {
            this.pool = pool;
        }

        @Override
        public void run() {
            try {
                pool.evict();
            } catch (Exception e) {
                // Ignore
            }
        }
    }
}
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.pool2.impl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.SwallowedExceptionListener;
import org.apache.commons.pool2.TestBaseObjectPool;
import org.apache.commons.pool2.VisitTracker;
import org.apache.commons.pool2.VisitTrackerFactory;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @version $Revision: 1569016 $
 */
public class TestGenericObjectPool extends TestBaseObjectPool {

    @Override
    protected ObjectPool<String> makeEmptyPool(int mincap) {
       GenericObjectPool<String> mtPool =
               new GenericObjectPool<String>(new SimpleFactory());
       mtPool.setMaxTotal(mincap);
       mtPool.setMaxIdle(mincap);
       return mtPool;
    }

    @Override
    protected ObjectPool<Object> makeEmptyPool(
            final PooledObjectFactory<Object> fac) {
        return new GenericObjectPool<Object>(fac);
    }

    @Override
    protected Object getNthObject(int n) {
        return String.valueOf(n);
    }

    @Before
    public void setUp() throws Exception {
        factory = new SimpleFactory();
        pool = new GenericObjectPool<String>(factory);
    }

    @After
    public void tearDown() throws Exception {
        String poolName = pool.getJmxName().toString();
        pool.clear();
        pool.close();
        pool = null;
        factory = null;

        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(new ObjectName(
                "org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
        // There should be no registered pools at this point
        int registeredPoolCount = result.size();
        StringBuilder msg = new StringBuilder("Current pool is: ");
        msg.append(poolName);
        msg.append("  Still open pools are: ");
        for (ObjectName name : result) {
            // Clean these up ready for the next test
            msg.append(name.toString());
            msg.append(" created via\n");
            msg.append(mbs.getAttribute(name, "CreationStackTrace"));
            msg.append('\n');
            mbs.unregisterMBean(name);
        }
        Assert.assertEquals(msg.toString(), 0, registeredPoolCount);
    }

    @Test(expected=IllegalArgumentException.class)
    public void testConstructorNullFactory() {
        // add dummy assert (won't be invoked because of IAE) to avoid "unused" warning
        assertNotNull(new GenericObjectPool<String>(null));
        // TODO this currently causes tearDown to report an error
        // Looks like GOP needs to call close() or jmxUnregister() before throwing IAE
    }

    @Test(timeout=60000)
    public void testConstructors() throws Exception {

        // Make constructor arguments all different from defaults
        int minIdle = 2;
        long maxWait = 3;
        int maxIdle = 4;
        int maxTotal = 5;
        long minEvictableIdleTimeMillis = 6;
        int numTestsPerEvictionRun = 7;
        boolean testOnBorrow = true;
        boolean testOnReturn = true;
        boolean testWhileIdle = true;
        long timeBetweenEvictionRunsMillis = 8;
        boolean blockWhenExhausted = false;
        boolean lifo = false;
        PooledObjectFactory<Object> dummyFactory = new DummyFactory();
        GenericObjectPool<Object> dummyPool =
                new GenericObjectPool<Object>(dummyFactory);
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
        assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(GenericObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN,
                dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_BORROW),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_ON_RETURN),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(GenericObjectPoolConfig.DEFAULT_LIFO),
                Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();

        GenericObjectPoolConfig config =
                new GenericObjectPoolConfig();
        config.setLifo(lifo);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setMaxTotal(maxTotal);
        config.setMaxWaitMillis(maxWait);
        config.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setTestWhileIdle(testWhileIdle);
        config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        config.setBlockWhenExhausted(blockWhenExhausted);
        dummyPool = new GenericObjectPool<Object>(dummyFactory, config);
        assertEquals(maxIdle, dummyPool.getMaxIdle());
        assertEquals(maxWait, dummyPool.getMaxWaitMillis());
        assertEquals(minIdle, dummyPool.getMinIdle());
        assertEquals(maxTotal, dummyPool.getMaxTotal());
        assertEquals(minEvictableIdleTimeMillis,
                dummyPool.getMinEvictableIdleTimeMillis());
        assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
        assertEquals(Boolean.valueOf(testOnBorrow),
                Boolean.valueOf(dummyPool.getTestOnBorrow()));
        assertEquals(Boolean.valueOf(testOnReturn),
                Boolean.valueOf(dummyPool.getTestOnReturn()));
        assertEquals(Boolean.valueOf(testWhileIdle),
                Boolean.valueOf(dummyPool.getTestWhileIdle()));
        assertEquals(timeBetweenEvictionRunsMillis,
                dummyPool.getTimeBetweenEvictionRunsMillis());
        assertEquals(Boolean.valueOf(blockWhenExhausted),
                Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
        assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
        dummyPool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedFail() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(false);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumIdle());
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlock() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(10L);
        String obj1 = pool.borrowObject();
        assertNotNull(obj1);
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
        pool.returnObject(obj1);
        pool.close();
    }

    @Test(timeout=60000)
    public void testWhenExhaustedBlockInterupt() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        String obj1 = pool.borrowObject();

        // Make sure on object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200000);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);
        wtt.interrupt();

        // Give interupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);

        // Return object to the pool
        pool.returnObject(obj1);

        // Bug POOL-162 - check there is now an object in the pool
        pool.setMaxWaitMillis(10L);
        String obj2 = null;
        try {
             obj2 = pool.borrowObject();
            assertNotNull(obj2);
        } catch(NoSuchElementException e) {
            // Not expected
            fail("NoSuchElementException not expected");
        }
        pool.returnObject(obj2);
        pool.close();

    }

    @Test(timeout=60000)
    public void testEvictWhileEmpty() throws Exception {
        pool.evict();
        pool.evict();
        pool.close();
    }

    /**
     * Tests addObject contention between ensureMinIdle triggered by
     * the Evictor with minIdle &gt; 0 and borrowObject.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictAddObjects() throws Exception {
        factory.setMakeLatency(300);
        factory.setMaxTotal(2);
        pool.setMaxTotal(2);
        pool.setMinIdle(1);
        pool.borrowObject(); // numActive = 1, numIdle = 0
        // Create a test thread that will run once and try a borrow after
        // 150ms fixed delay
        TestThread borrower = new TestThread(pool, 1, 150, false);
        Thread borrowerThread = new Thread(borrower);
        // Set evictor to run in 100 ms - will create idle instance
        pool.setTimeBetweenEvictionRunsMillis(100);
        borrowerThread.start();  // Off to the races
        borrowerThread.join();
        assertTrue(!borrower.failed());
    }

    @Test(timeout=60000)
    public void testEvictLIFO() throws Exception {
        checkEvict(true);
    }

    @Test(timeout=60000)
    public void testEvictFIFO() throws Exception {
        checkEvict(false);
    }

    private void checkEvict(boolean lifo) throws Exception {
        // yea this is hairy but it tests all the code paths in GOP.evict()
        pool.setSoftMinEvictableIdleTimeMillis(10);
        pool.setMinIdle(2);
        pool.setTestWhileIdle(true);
        pool.setLifo(lifo);
        PoolUtils.prefill(pool, 5);
        pool.evict();
        factory.setEvenValid(false);
        factory.setOddValid(false);
        factory.setThrowExceptionOnActivate(true);
        pool.evict();
        PoolUtils.prefill(pool, 5);
        factory.setThrowExceptionOnActivate(false);
        factory.setThrowExceptionOnPassivate(true);
        pool.evict();
        factory.setThrowExceptionOnPassivate(false);
        factory.setEvenValid(true);
        factory.setOddValid(true);
        Thread.sleep(125);
        pool.evict();
        assertEquals(2, pool.getNumIdle());
    }

    /**
     * Test to make sure evictor visits least recently used objects first,
     * regardless of FIFO/LIFO.
     *
     * JIRA: POOL-86
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testEvictionOrder() throws Exception {
        checkEvictionOrder(false);
        tearDown();
        setUp();
        checkEvictionOrder(true);
    }

    private void checkEvictionOrder(boolean lifo) throws Exception {
        checkEvictionOrderPart1(lifo);
        tearDown();
        setUp();
        checkEvictionOrderPart2(lifo);
    }

    private void checkEvictionOrderPart1(boolean lifo) throws Exception {
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        // Order, oldest to youngest, is "0", "1", ...,"4"
        pool.evict(); // Should evict "0" and "1"
        Object obj = pool.borrowObject();
        assertTrue("oldest not evicted", !obj.equals("0"));
        assertTrue("second oldest not evicted", !obj.equals("1"));
        // 2 should be next out for FIFO, 4 for LIFO
        assertEquals("Wrong instance returned", lifo ? "4" : "2" , obj);
    }

    private void checkEvictionOrderPart2(boolean lifo) throws Exception {
        // Two eviction runs in sequence
        pool.setNumTestsPerEvictionRun(2);
        pool.setMinEvictableIdleTimeMillis(100);
        pool.setLifo(lifo);
        for (int i = 0; i < 5; i++) {
            pool.addObject();
            Thread.sleep(100);
        }
        pool.evict(); // Should evict "0" and "1"
        pool.evict(); // Should evict "2" and "3"
        Object obj = pool.borrowObject();
        assertEquals("Wrong instance remaining in pool", "4", obj);
    }

    /**
     * Verifies that the evictor visits objects in expected order
     * and frequency.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testEvictorVisiting() throws Exception {
        checkEvictorVisiting(true);
        checkEvictorVisiting(false);
    }

    private void checkEvictorVisiting(boolean lifo) throws Exception {
        VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<Object>();
        GenericObjectPool<VisitTracker<Object>> trackerPool =
                new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(2);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // Visit oldest 2 - 0 and 1
        VisitTracker<Object> obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        //  borrow, return, borrow, return
        //  FIFO will move 0 and 1 to end
        //  LIFO, 7 out, then in, then out, then in
        trackerPool.evict();  // Should visit 2 and 3 in either case
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() >= 4) {
                assertEquals("Unexpected instance visited " + tracker.getId(),
                        0, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        trackerFactory = new VisitTrackerFactory<Object>();
        trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
        trackerPool.setNumTestsPerEvictionRun(3);
        trackerPool.setMinEvictableIdleTimeMillis(-1);
        trackerPool.setTestWhileIdle(true);
        trackerPool.setLifo(lifo);
        trackerPool.setTestOnReturn(false);
        trackerPool.setTestOnBorrow(false);
        for (int i = 0; i < 8; i++) {
            trackerPool.addObject();
        }
        trackerPool.evict(); // 0, 1, 2
        trackerPool.evict(); // 3, 4, 5
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        obj = trackerPool.borrowObject();
        trackerPool.returnObject(obj);
        // borrow, return, borrow, return
        //  FIFO 3,4,5,6,7,0,1,2
        //  LIFO 7,6,5,4,3,2,1,0
        // In either case, pointer should be at 6
        trackerPool.evict();
        // Should hit 6,7,0 - 0 for second time
        for (int i = 0; i < 8; i++) {
            VisitTracker<Object> tracker = trackerPool.borrowObject();
            if (tracker.getId() != 0) {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        1, tracker.getValidateCount());
            } else {
                assertEquals("Instance " +  tracker.getId() +
                        " visited wrong number of times.",
                        2, tracker.getValidateCount());
            }
        }
        trackerPool.close();

        // Randomly generate a pools with random numTests
        // and make sure evictor cycles through elements appropriately
        int[] smallPrimes = {2, 3, 5, 7};
        Random random = new Random();
        random.setSeed(System.currentTimeMillis());
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 5; j++) {
                trackerPool = new GenericObjectPool<VisitTracker<Object>>(trackerFactory);
                trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
                trackerPool.setMinEvictableIdleTimeMillis(-1);
                trackerPool.setTestWhileIdle(true);
                trackerPool.setLifo(lifo);
                trackerPool.setTestOnReturn(false);
                trackerPool.setTestOnBorrow(false);
                trackerPool.setMaxIdle(-1);
                int instanceCount = 10 + random.nextInt(20);
                trackerPool.setMaxTotal(instanceCount);
                for (int k = 0; k < instanceCount; k++) {
                    trackerPool.addObject();
                }

                // Execute a random number of evictor runs
                int runs = 10 + random.nextInt(50);
                for (int k = 0; k < runs; k++) {
                    trackerPool.evict();
                }

                // Number of times evictor should have cycled through the pool
                int cycleCount = (runs * trackerPool.getNumTestsPerEvictionRun()) /
                        instanceCount;

                // Look at elements and make sure they are visited cycleCount
                // or cycleCount + 1 times
                VisitTracker<Object> tracker = null;
                int visitCount = 0;
                for (int k = 0; k < instanceCount; k++) {
                    tracker = trackerPool.borrowObject();
                    assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
                    visitCount = tracker.getValidateCount();
                    assertTrue(visitCount >= cycleCount &&
                            visitCount <= cycleCount + 1);
                }
                trackerPool.close();
            }
        }
    }

    @Test(timeout=60000)
    public void testExceptionOnPassivateDuringReturn() throws Exception {
        String obj = pool.borrowObject();
        factory.setThrowExceptionOnPassivate(true);
        pool.returnObject(obj);
        assertEquals(0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringBorrow() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnBorrow(true);
        pool.borrowObject();
        factory.setValid(false); // Make validation fail on next borrow attempt
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnDestroyDuringReturn() throws Exception {
        factory.setThrowExceptionOnDestroy(true);
        pool.setTestOnReturn(true);
        String obj1 = pool.borrowObject();
        pool.borrowObject();
        factory.setValid(false); // Make validation fail
        pool.returnObject(obj1);
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testExceptionOnActivateDuringBorrow() throws Exception {
        String obj1 = pool.borrowObject();
        String obj2 = pool.borrowObject();
        pool.returnObject(obj1);
        pool.returnObject(obj2);
        factory.setThrowExceptionOnActivate(true);
        factory.setEvenValid(false);
        // Activation will now throw every other time
        // First attempt throws, but loop continues and second succeeds
        String obj = pool.borrowObject();
        assertEquals(1, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);
        factory.setValid(false);
        // Validation will now fail on activation when borrowObject returns
        // an idle instance, and then when attempting to create a new instance
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        assertEquals(0, pool.getNumActive());
        assertEquals(0, pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testNegativeMaxTotal() throws Exception {
        pool.setMaxTotal(-1);
        pool.setBlockWhenExhausted(false);
        String obj = pool.borrowObject();
        assertEquals(getNthObject(0),obj);
        pool.returnObject(obj);
    }

    @Test(timeout=60000)
    public void testMaxIdle() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(8);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals((i < 8 ? i+1 : 8),pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxIdleZero() throws Exception {
        pool.setMaxTotal(100);
        pool.setMaxIdle(0);
        String[] active = new String[100];
        for(int i=0;i<100;i++) {
            active[i] = pool.borrowObject();
        }
        assertEquals(100,pool.getNumActive());
        assertEquals(0,pool.getNumIdle());
        for(int i=0;i<100;i++) {
            pool.returnObject(active[i]);
            assertEquals(99 - i,pool.getNumActive());
            assertEquals(0, pool.getNumIdle());
        }
    }

    @Test(timeout=60000)
    public void testMaxTotal() throws Exception {
        pool.setMaxTotal(3);
        pool.setBlockWhenExhausted(false);

        pool.borrowObject();
        pool.borrowObject();
        pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testTimeoutNoLeak() throws Exception {
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(10);
        pool.setBlockWhenExhausted(true);
        String obj = pool.borrowObject();
        String obj2 = pool.borrowObject();
        try {
            pool.borrowObject();
            fail("Expecting NoSuchElementException");
        } catch (NoSuchElementException ex) {
            // expected
        }
        pool.returnObject(obj2);
        pool.returnObject(obj);

        pool.borrowObject();
        pool.borrowObject();
    }

    @Test(timeout=60000)
    public void testMaxTotalZero() throws Exception {
        pool.setMaxTotal(0);
        pool.setBlockWhenExhausted(false);

        try {
            pool.borrowObject();
            fail("Expected NoSuchElementException");
        } catch(NoSuchElementException e) {
            // expected
        }
    }

    @Test(timeout=60000)
    public void testMaxTotalUnderLoad() {
        // Config
        int numThreads = 199; // And main thread makes a round 200.
        int numIter = 20;
        int delay = 25;
        int maxTotal = 10;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            // Factor of 2 on iterations so main thread does work whilst other
            // threads are running. Factor of 2 on delay so average delay for
            // other threads == actual delay for main thread
            threads[i] = new TestThread(pool, numIter * 2, delay * 2);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        // Give the threads a chance to start doing some work
        try {
            Thread.sleep(5000);
        } catch(InterruptedException e) {
            // ignored
        }

        for (int i = 0; i < numIter; i++) {
            String obj = null;
            try {
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                obj = pool.borrowObject();
                // Under load, observed _numActive > _maxTotal
                if (pool.getNumActive() > pool.getMaxTotal()) {
                    throw new IllegalStateException("Too many active objects");
                }
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
            } catch (Exception e) {
                // Shouldn't happen
                e.printStackTrace();
                fail("Exception on borrow");
            } finally {
                if (obj != null) {
                    try {
                        pool.returnObject(obj);
                    } catch (Exception e) {
                        // Ignore
                    }
                }
            }
        }

        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testSettersAndGetters() throws Exception {
        {
            // The object receives an Exception during its creation to prevent
            // memory leaks. See BaseGenericObjectPool constructor for more details.
            assertTrue(false == "".equals(pool.getCreationStackTrace()));
        }
        {
            assertEquals(0, pool.getBorrowedCount());
        }
        {
            assertEquals(0, pool.getReturnedCount());
        }
        {
            assertEquals(0, pool.getCreatedCount());
        }
        {
            assertEquals(0, pool.getDestroyedCount());
        }
        {
            assertEquals(0, pool.getDestroyedByEvictorCount());
        }
        {
            assertEquals(0, pool.getDestroyedByBorrowValidationCount());
        }
        {
            assertEquals(0, pool.getMeanActiveTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanIdleTimeMillis());
        }
        {
            assertEquals(0, pool.getMeanBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getMaxBorrowWaitTimeMillis());
        }
        {
            assertEquals(0, pool.getNumIdle());
        }
        {
            pool.setMaxTotal(123);
            assertEquals(123,pool.getMaxTotal());
        }
        {
            pool.setMaxIdle(12);
            assertEquals(12,pool.getMaxIdle());
        }
        {
            pool.setMaxWaitMillis(1234L);
            assertEquals(1234L,pool.getMaxWaitMillis());
        }
        {
            pool.setMinEvictableIdleTimeMillis(12345L);
            assertEquals(12345L,pool.getMinEvictableIdleTimeMillis());
        }
        {
            pool.setNumTestsPerEvictionRun(11);
            assertEquals(11,pool.getNumTestsPerEvictionRun());
        }
        {
            pool.setTestOnBorrow(true);
            assertTrue(pool.getTestOnBorrow());
            pool.setTestOnBorrow(false);
            assertTrue(!pool.getTestOnBorrow());
        }
        {
            pool.setTestOnReturn(true);
            assertTrue(pool.getTestOnReturn());
            pool.setTestOnReturn(false);
            assertTrue(!pool.getTestOnReturn());
        }
        {
            pool.setTestWhileIdle(true);
            assertTrue(pool.getTestWhileIdle());
            pool.setTestWhileIdle(false);
            assertTrue(!pool.getTestWhileIdle());
        }
        {
            pool.setTimeBetweenEvictionRunsMillis(11235L);
            assertEquals(11235L,pool.getTimeBetweenEvictionRunsMillis());
        }
        {
            pool.setSoftMinEvictableIdleTimeMillis(12135L);
            assertEquals(12135L,pool.getSoftMinEvictableIdleTimeMillis());
        }
        {
            pool.setBlockWhenExhausted(true);
            assertTrue(pool.getBlockWhenExhausted());
            pool.setBlockWhenExhausted(false);
            assertFalse(pool.getBlockWhenExhausted());
        }
    }

    @Test(timeout=60000)
    public void testDefaultConfiguration() throws Exception {
        assertConfiguration(new GenericObjectPoolConfig(),pool);
    }

    @Test(timeout=60000)
    public void testSetConfig() throws Exception {
        GenericObjectPoolConfig expected = new GenericObjectPoolConfig();
        assertConfiguration(expected,pool);
        expected.setMaxTotal(2);
        expected.setMaxIdle(3);
        expected.setMaxWaitMillis(5L);
        expected.setMinEvictableIdleTimeMillis(7L);
        expected.setNumTestsPerEvictionRun(9);
        expected.setTestOnCreate(true);
        expected.setTestOnBorrow(true);
        expected.setTestOnReturn(true);
        expected.setTestWhileIdle(true);
        expected.setTimeBetweenEvictionRunsMillis(11L);
        expected.setBlockWhenExhausted(false);
        pool.setConfig(expected);
        assertConfiguration(expected,pool);
    }

    @Test(timeout=60000)
    public void testStartAndStopEvictor() throws Exception {
        // set up pool without evictor
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(6);
        pool.setMinEvictableIdleTimeMillis(100L);

        for(int j=0;j<2;j++) {
            // populate the pool
            {
                String[] active = new String[6];
                for(int i=0;i<6;i++) {
                    active[i] = pool.borrowObject();
                }
                for(int i=0;i<6;i++) {
                    pool.returnObject(active[i]);
                }
            }

            // note that it stays populated
            assertEquals("Should have 6 idle",6,pool.getNumIdle());

            // start the evictor
            pool.setTimeBetweenEvictionRunsMillis(50L);

            // wait a second (well, .2 seconds)
            try { Thread.sleep(200L); } catch(InterruptedException e) { }

            // assert that the evictor has cleared out the pool
            assertEquals("Should have 0 idle",0,pool.getNumIdle());

            // stop the evictor
            pool.startEvictor(0L);
        }
    }

    @Test(timeout=60000)
    public void testEvictionWithNegativeNumTests() throws Exception {
        // when numTestsPerEvictionRun is negative, it represents a fraction of the idle objects to test
        pool.setMaxIdle(6);
        pool.setMaxTotal(6);
        pool.setNumTestsPerEvictionRun(-2);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);

        String[] active = new String[6];
        for(int i=0;i<6;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<6;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 6 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 6);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should at most 3 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 3);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertTrue("Should be at most 2 idle, found " + pool.getNumIdle(),pool.getNumIdle() <= 2);
        try { Thread.sleep(100L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    @Test(timeout=60000)
    public void testEviction() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(100);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());

        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 500 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 500);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 400 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 400);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 300 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 300);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 200 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 200);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertTrue("Should be less than 100 idle, found " + pool.getNumIdle(),pool.getNumIdle() < 100);
        try { Thread.sleep(600L); } catch(InterruptedException e) { }
        assertEquals("Should be zero idle, found " + pool.getNumIdle(),0,pool.getNumIdle());
    }

    public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {

        private AtomicInteger callCount = new AtomicInteger(0);

        @Override
        public boolean evict(EvictionConfig config, PooledObject<T> underTest,
                int idleCount) {
            if (callCount.incrementAndGet() > 1500) {
                return true;
            } else {
                return false;
            }
        }
    }

    @Test(timeout=60000)
    public void testEvictionPolicy() throws Exception {
        pool.setMaxIdle(500);
        pool.setMaxTotal(500);
        pool.setNumTestsPerEvictionRun(500);
        pool.setMinEvictableIdleTimeMillis(250L);
        pool.setTimeBetweenEvictionRunsMillis(500L);
        pool.setTestWhileIdle(true);

        // ClassNotFoundException
        try {
            pool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis()));
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // InstantiationException
        try {
            pool.setEvictionPolicyClassName(java.io.Serializable.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        // IllegalAccessException
        try {
            pool.setEvictionPolicyClassName(java.util.Collections.class.getName());
            fail("setEvictionPolicyClassName must throw an error if the class name is invalid.");
        } catch (IllegalArgumentException e) {
            // expected
        }

        pool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
        assertEquals(TestEvictionPolicy.class.getName(), pool.getEvictionPolicyClassName());

        String[] active = new String[500];
        for(int i=0;i<500;i++) {
            active[i] = pool.borrowObject();
        }
        for(int i=0;i<500;i++) {
            pool.returnObject(active[i]);
        }

        // Eviction policy ignores first 1500 attempts to evict and then always
        // evicts. After 1s, there should have been two runs of 500 tests so no
        // evictions
        try { Thread.sleep(1000L); } catch(InterruptedException e) { }
        assertEquals("Should be 500 idle", 500, pool.getNumIdle());
        // A further 1s wasn't enough so allow 2s for the evictor to clear out
        // all of the idle objects.
        try { Thread.sleep(2000L); } catch(InterruptedException e) { }
        assertEquals("Should be 0 idle", 0, pool.getNumIdle());
    }


    @Test(timeout=60000)
    public void testEvictionSoftMinIdle() throws Exception {
        class TimeTest extends BasePooledObjectFactory<TimeTest> {
            private final long createTime;
            public TimeTest() {
                createTime = System.currentTimeMillis();
            }
            @Override
            public TimeTest create() throws Exception {
                return new TimeTest();
            }
            @Override
            public PooledObject<TimeTest> wrap(TimeTest value) {
                return new DefaultPooledObject<TimeTest>(value);
            }
            public long getCreateTime() {
                return createTime;
            }
        }

        GenericObjectPool<TimeTest> timePool =
            new GenericObjectPool<TimeTest>(new TimeTest());

        timePool.setMaxIdle(5);
        timePool.setMaxTotal(5);
        timePool.setNumTestsPerEvictionRun(5);
        timePool.setMinEvictableIdleTimeMillis(3000L);
        timePool.setSoftMinEvictableIdleTimeMillis(1000L);
        timePool.setMinIdle(2);

        TimeTest[] active = new TimeTest[5];
        Long[] creationTime = new Long[5] ;
        for(int i=0;i<5;i++) {
            active[i] = timePool.borrowObject();
            creationTime[i] = Long.valueOf((active[i]).getCreateTime());
        }

        for(int i=0;i<5;i++) {
            timePool.returnObject(active[i]);
        }

        // Soft evict all but minIdle(2)
        Thread.sleep(1500L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 2, timePool.getNumIdle());

        // Hard evict the rest.
        Thread.sleep(2000L);
        timePool.evict();
        assertEquals("Idle count different than expected.", 0, timePool.getNumIdle());
        timePool.close();
    }

    @Test(timeout=60000)
    public void testEvictionInvalid() throws Exception {

        final GenericObjectPool<Object> invalidFactoryPool =
                new GenericObjectPool<Object>(new InvalidFactory());

        invalidFactoryPool.setMaxIdle(1);
        invalidFactoryPool.setMaxTotal(1);
        invalidFactoryPool.setTestOnBorrow(false);
        invalidFactoryPool.setTestOnReturn(false);
        invalidFactoryPool.setTestWhileIdle(true);
        invalidFactoryPool.setMinEvictableIdleTimeMillis(100000);
        invalidFactoryPool.setNumTestsPerEvictionRun(1);

        Object p = invalidFactoryPool.borrowObject();
        invalidFactoryPool.returnObject(p);

        // Run eviction in a separate thread
        Thread t = new EvictionThread<Object>(invalidFactoryPool);
        t.start();

        // Sleep to make sure evictor has started
        Thread.sleep(300);

        try {
            invalidFactoryPool.borrowObject(1);
        } catch (NoSuchElementException nsee) {
            // Ignore
        }

        // Make sure evictor has finished
        Thread.sleep(1000);

        // Should have an empty pool
        assertEquals("Idle count different than expected.", 0, invalidFactoryPool.getNumIdle());
        assertEquals("Total count different than expected.", 0, invalidFactoryPool.getNumActive());
        invalidFactoryPool.close();
    }

    /**
     * POOL-231 - verify that concurrent invalidates of the same object do not
     * corrupt pool destroyCount.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testConcurrentInvalidate() throws Exception {
        // Get allObjects and idleObjects loaded with some instances
        final int nObjects = 1000;
        pool.setMaxTotal(nObjects);
        pool.setMaxIdle(nObjects);
        final String[] obj = new String[nObjects];
        for (int i = 0; i < nObjects; i++) {
            obj[i] = pool.borrowObject();
        }
        for (int i = 0; i < nObjects; i++) {
            if (i % 2 == 0) {
                pool.returnObject(obj[i]);
            }
        }
        final int nThreads = 20;
        final int nIterations = 60;
        final InvalidateThread[] threads = new InvalidateThread[nThreads];
        // Randomly generated list of distinct invalidation targets
        final ArrayList<Integer> targets = new ArrayList<Integer>();
        final Random random = new Random();
        for (int j = 0; j < nIterations; j++) {
            // Get a random invalidation target
            Integer targ = Integer.valueOf(random.nextInt(nObjects));
            while (targets.contains(targ)) {
                targ = Integer.valueOf(random.nextInt(nObjects));
            }
            targets.add(targ);
            // Launch nThreads threads all trying to invalidate the target
            for (int i = 0; i < nThreads; i++) {
                threads[i] = new InvalidateThread(pool, obj[targ.intValue()]);
            }
            for (int i = 0; i < nThreads; i++) {
                new Thread(threads[i]).start();
            }
            boolean done = false;
            while (!done) {
                done = true;
                for (int i = 0; i < nThreads; i++) {
                    done = done && threads[i].complete();
                }
                Thread.sleep(100);
            }
        }
        Assert.assertEquals(nIterations, pool.getDestroyedCount());
    }

    /**
     * Attempts to invalidate an object, swallowing IllegalStateException.
     */
    static class InvalidateThread implements Runnable {
        private final String obj;
        private final ObjectPool<String> pool;
        private boolean done = false;
        public InvalidateThread(ObjectPool<String> pool, String obj) {
            this.obj = obj;
            this.pool = pool;
        }
        @Override
        public void run() {
            try {
                pool.invalidateObject(obj);
            } catch (IllegalStateException ex) {
                // Ignore
            } catch (Exception ex) {
                Assert.fail("Unexpected exception " + ex.toString());
            } finally {
                done = true;
            }
        }
        public boolean complete() {
            return done;
        }
    }

    @Test(timeout=60000)
    public void testMinIdle() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[5];
        active[0] = pool.borrowObject();

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=1 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    @Test(timeout=60000)
    public void testMinIdleMaxTotal() throws Exception {
        pool.setMaxIdle(500);
        pool.setMinIdle(5);
        pool.setMaxTotal(10);
        pool.setNumTestsPerEvictionRun(0);
        pool.setMinEvictableIdleTimeMillis(50L);
        pool.setTimeBetweenEvictionRunsMillis(100L);
        pool.setTestWhileIdle(true);

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        String[] active = new String[10];

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 5 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 5);

        for(int i=0 ; i<5 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);

        for(int i=0 ; i<10 ; i++) {
            active[i] = pool.borrowObject();
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 0 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 0);

        for(int i=0 ; i<10 ; i++) {
            pool.returnObject(active[i]);
        }

        try { Thread.sleep(150L); } catch(InterruptedException e) { }
        assertTrue("Should be 10 idle, found " + pool.getNumIdle(),pool.getNumIdle() == 10);
    }

    /**
     * Kicks off <numThreads> test threads, each of which will go through
     * <iterations> borrow-return cycles with random delay times <= delay
     * in between.
     */
    private void runTestThreads(int numThreads, int iterations, int delay) {
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool,iterations,delay);
            Thread t = new Thread(threads[i]);
            t.start();
        }
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    @Test(timeout=60000)
    public void testThreaded1() throws Exception {
        pool.setMaxTotal(15);
        pool.setMaxIdle(15);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(20, 100, 50);
    }

    /**
     * Verifies that maxTotal is not exceeded when factory destroyObject
     * has high latency, testOnReturn is set and there is high incidence of
     * validation failures.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMaxTotalInvariant() throws Exception {
        int maxTotal = 15;
        factory.setEvenValid(false);     // Every other validation fails
        factory.setDestroyLatency(100);  // Destroy takes 100 ms
        factory.setMaxTotal(maxTotal); // (makes - destroys) bound
        factory.setValidationEnabled(true);
        pool.setMaxTotal(maxTotal);
        pool.setMaxIdle(-1);
        pool.setTestOnReturn(true);
        pool.setMaxWaitMillis(1000L);
        runTestThreads(5, 10, 50);
    }

    @Test(timeout=60000)
    public void testConcurrentBorrowAndEvict() throws Exception {

        pool.setMaxTotal(1);
        pool.addObject();

        for( int i=0; i<5000; i++) {
            ConcurrentBorrowAndEvictThread one =
                    new ConcurrentBorrowAndEvictThread(true);
            ConcurrentBorrowAndEvictThread two =
                    new ConcurrentBorrowAndEvictThread(false);

            one.start();
            two.start();
            one.join();
            two.join();

            pool.returnObject(one.obj);

            /* Uncomment this for a progress indication
            if (i % 10 == 0) {
                System.out.println(i/10);
            }
            */
        }
    }

    /**
     * POOL-189
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testWhenExhaustedBlockClosePool() throws Exception {
        pool.setMaxTotal(1);
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(-1);
        Object obj1 = pool.borrowObject();

        // Make sure an object was obtained
        assertNotNull(obj1);

        // Create a separate thread to try and borrow another object
        WaitingTestThread wtt = new WaitingTestThread(pool, 200);
        wtt.start();
        // Give wtt time to start
        Thread.sleep(200);

        // close the pool (Bug POOL-189)
        pool.close();

        // Give interrupt time to take effect
        Thread.sleep(200);

        // Check thread was interrupted
        assertTrue(wtt._thrown instanceof InterruptedException);
    }

    private class ConcurrentBorrowAndEvictThread extends Thread {
        private boolean borrow;
        public String obj;

        public ConcurrentBorrowAndEvictThread(boolean borrow) {
            this.borrow = borrow;
        }

        @Override
        public void run() {
            try {
                if (borrow) {
                    obj = pool.borrowObject();
                } else {
                    pool.evict();
                }
            } catch (Exception e) { /* Ignore */}
        }
    }

    static class TestThread implements Runnable {
        private final java.util.Random _random = new java.util.Random();

        // Thread config items
        private final ObjectPool<String> _pool;
        private final int _iter;
        private final int _delay;
        private final boolean _randomDelay;
        private final Object _expectedObject;

        private volatile boolean _complete = false;
        private volatile boolean _failed = false;
        private volatile Throwable _error;

        public TestThread(ObjectPool<String> pool) {
            this(pool, 100, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter) {
            this(pool, iter, 50, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay) {
            this(pool, iter, delay, true, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay) {
            this(pool, iter, delay, randomDelay, null);
        }

        public TestThread(ObjectPool<String> pool, int iter, int delay,
                boolean randomDelay, Object obj) {
            _pool = pool;
            _iter = iter;
            _delay = delay;
            _randomDelay = randomDelay;
            _expectedObject = obj;
        }

        public boolean complete() {
            return _complete;
        }

        public boolean failed() {
            return _failed;
        }

        @Override
        public void run() {
            for(int i=0;i<_iter;i++) {
                long delay =
                    _randomDelay ? (long)_random.nextInt(_delay) : _delay;
                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                String obj = null;
                try {
                    obj = _pool.borrowObject();
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }

                if (_expectedObject != null && !_expectedObject.equals(obj)) {
                    _error = new Throwable("Expected: "+_expectedObject+ " found: "+obj);
                    _failed = true;
                    _complete = true;
                    break;
                }

                try {
                    Thread.sleep(delay);
                } catch(InterruptedException e) {
                    // ignored
                }
                try {
                    _pool.returnObject(obj);
                } catch(Exception e) {
                    _error = e;
                    _failed = true;
                    _complete = true;
                    break;
                }
            }
            _complete = true;
        }
    }

    @Test(timeout=60000)
    public void testFIFO() throws Exception {
        String o = null;
        pool.setLifo(false);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Oldest", "0", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Youngest", "2", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testLIFO() throws Exception {
        String o = null;
        pool.setLifo(true);
        pool.addObject(); // "0"
        pool.addObject(); // "1"
        pool.addObject(); // "2"
        assertEquals("Youngest", "2", pool.borrowObject());
        assertEquals("Middle", "1", pool.borrowObject());
        assertEquals("Oldest", "0", pool.borrowObject());
        o = pool.borrowObject();
        assertEquals("new-3", "3", o);
        pool.returnObject(o);
        assertEquals("returned-3", o, pool.borrowObject());
        assertEquals("new-4", "4", pool.borrowObject());
    }

    @Test(timeout=60000)
    public void testAddObject() throws Exception {
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        pool.addObject();
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
        String obj = pool.borrowObject();
        assertEquals("should be zero idle", 0, pool.getNumIdle());
        assertEquals("should be one active", 1, pool.getNumActive());
        pool.returnObject(obj);
        assertEquals("should be one idle", 1, pool.getNumIdle());
        assertEquals("should be zero active", 0, pool.getNumActive());
    }

    protected GenericObjectPool<String> pool = null;

    private SimpleFactory factory = null;

    private void assertConfiguration(GenericObjectPoolConfig expected, GenericObjectPool<?> actual) throws Exception {
        assertEquals("testOnCreate",Boolean.valueOf(expected.getTestOnCreate()),
                Boolean.valueOf(actual.getTestOnCreate()));
        assertEquals("testOnBorrow",Boolean.valueOf(expected.getTestOnBorrow()),
                Boolean.valueOf(actual.getTestOnBorrow()));
        assertEquals("testOnReturn",Boolean.valueOf(expected.getTestOnReturn()),
                Boolean.valueOf(actual.getTestOnReturn()));
        assertEquals("testWhileIdle",Boolean.valueOf(expected.getTestWhileIdle()),
                Boolean.valueOf(actual.getTestWhileIdle()));
        assertEquals("whenExhaustedAction",
                Boolean.valueOf(expected.getBlockWhenExhausted()),
                Boolean.valueOf(actual.getBlockWhenExhausted()));
        assertEquals("maxTotal",expected.getMaxTotal(),actual.getMaxTotal());
        assertEquals("maxIdle",expected.getMaxIdle(),actual.getMaxIdle());
        assertEquals("maxWait",expected.getMaxWaitMillis(),actual.getMaxWaitMillis());
        assertEquals("minEvictableIdleTimeMillis",expected.getMinEvictableIdleTimeMillis(),actual.getMinEvictableIdleTimeMillis());
        assertEquals("numTestsPerEvictionRun",expected.getNumTestsPerEvictionRun(),actual.getNumTestsPerEvictionRun());
        assertEquals("timeBetweenEvictionRunsMillis",expected.getTimeBetweenEvictionRunsMillis(),actual.getTimeBetweenEvictionRunsMillis());
    }

    public static class SimpleFactory implements PooledObjectFactory<String> {
        public SimpleFactory() {
            this(true);
        }
        public SimpleFactory(boolean valid) {
            this(valid,valid);
        }
        public SimpleFactory(boolean evalid, boolean ovalid) {
            evenValid = evalid;
            oddValid = ovalid;
        }
        public synchronized void setValid(boolean valid) {
            setEvenValid(valid);
            setOddValid(valid);
        }
        public synchronized void setEvenValid(boolean valid) {
            evenValid = valid;
        }
        public synchronized void setOddValid(boolean valid) {
            oddValid = valid;
        }
        public synchronized void setThrowExceptionOnPassivate(boolean bool) {
            exceptionOnPassivate = bool;
        }
        public synchronized void setMaxTotal(int maxTotal) {
            this.maxTotal = maxTotal;
        }
        public synchronized void setDestroyLatency(long destroyLatency) {
            this.destroyLatency = destroyLatency;
        }
        public synchronized void setMakeLatency(long makeLatency) {
            this.makeLatency = makeLatency;
        }
        public synchronized void setValidateLatency(long validateLatency) {
            this.validateLatency = validateLatency;
        }
        @Override
        public PooledObject<String> makeObject() {
            final long waitLatency;
            synchronized(this) {
                activeCount++;
                if (activeCount > maxTotal) {
                    throw new IllegalStateException(
                        "Too many active instances: " + activeCount);
                }
                waitLatency = makeLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            final int counter;
            synchronized(this) {
                counter = makeCounter++;
            }
            return new DefaultPooledObject<String>(String.valueOf(counter));
        }
        @Override
        public void destroyObject(PooledObject<String> obj) throws Exception {
            final long waitLatency;
            final boolean hurl;
            synchronized(this) {
                waitLatency = destroyLatency;
                hurl = exceptionOnDestroy;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            synchronized(this) {
                activeCount--;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        @Override
        public boolean validateObject(PooledObject<String> obj) {
            final boolean validate;
            final boolean evenTest;
            final boolean oddTest;
            final long waitLatency;
            final int counter;
            synchronized(this) {
                validate = enableValidation;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
                waitLatency = validateLatency;
            }
            if (waitLatency > 0) {
                doWait(waitLatency);
            }
            if (validate) {
                return counter%2 == 0 ? evenTest : oddTest;
            }
            else {
                return true;
            }
        }
        @Override
        public void activateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            final boolean evenTest;
            final boolean oddTest;
            final int counter;
            synchronized(this) {
                hurl = exceptionOnActivate;
                evenTest = evenValid;
                oddTest = oddValid;
                counter = validateCounter++;
            }
            if (hurl) {
                if (!(counter%2 == 0 ? evenTest : oddTest)) {
                    throw new Exception();
                }
            }
        }
        @Override
        public void passivateObject(PooledObject<String> obj) throws Exception {
            final boolean hurl;
            synchronized(this) {
                hurl = exceptionOnPassivate;
            }
            if (hurl) {
                throw new Exception();
            }
        }
        int makeCounter = 0;
        int validateCounter = 0;
        int activeCount = 0;
        boolean evenValid = true;
        boolean oddValid = true;
        boolean exceptionOnPassivate = false;
        boolean exceptionOnActivate = false;
        boolean exceptionOnDestroy = false;
        boolean enableValidation = true;
        long destroyLatency = 0;
        long makeLatency = 0;
        long validateLatency = 0;
        int maxTotal = Integer.MAX_VALUE;

        public synchronized boolean isThrowExceptionOnActivate() {
            return exceptionOnActivate;
        }

        public synchronized void setThrowExceptionOnActivate(boolean b) {
            exceptionOnActivate = b;
        }

        public synchronized void setThrowExceptionOnDestroy(boolean b) {
            exceptionOnDestroy = b;
        }

        public synchronized boolean isValidationEnabled() {
            return enableValidation;
        }

        public synchronized void setValidationEnabled(boolean b) {
            enableValidation = b;
        }

        public synchronized int getMakeCounter() {
            return makeCounter;
        }

        private void doWait(long latency) {
            try {
                Thread.sleep(latency);
            } catch (InterruptedException ex) {
                // ignore
            }
        }
    }
    @Override
    protected boolean isLifo() {
        return true;
    }

    @Override
    protected boolean isFifo() {
        return false;
    }

    /*
     * Note: This test relies on timing for correct execution. There *should* be
     * enough margin for this to work correctly on most (all?) systems but be
     * aware of this if you see a failure of this test.
     */
    @Test(timeout=60000)
    public void testBorrowObjectFairness() {

        // Config
        int numThreads = 30;
        int maxTotal = 10;

        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTimeBetweenEvictionRunsMillis(-1);

        // Start threads to borrow objects
        TestThread[] threads = new TestThread[numThreads];
        for(int i=0;i<numThreads;i++) {
            threads[i] = new TestThread(pool, 1, 2000, false, String.valueOf(i % maxTotal));
            Thread t = new Thread(threads[i]);
            t.start();
            // Short delay to ensure threads start in correct order
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                fail(e.toString());
            }
        }

        // Wait for threads to finish
        for(int i=0;i<numThreads;i++) {
            while(!(threads[i]).complete()) {
                try {
                    Thread.sleep(500L);
                } catch(InterruptedException e) {
                    // ignored
                }
            }
            if(threads[i].failed()) {
                fail("Thread "+i+" failed: "+threads[i]._error.toString());
            }
        }
    }

    /**
     * On first borrow, first object fails validation, second object is OK.
     * Subsequent borrows are OK. This was POOL-152.
     */
    @Test(timeout=60000)
    public void testBrokenFactoryShouldNotBlockPool() {
        int maxTotal = 1;

        factory.setMaxTotal(maxTotal);
        pool.setMaxTotal(maxTotal);
        pool.setBlockWhenExhausted(true);
        pool.setTestOnBorrow(true);

        // First borrow object will need to create a new object which will fail
        // validation.
        String obj = null;
        Exception ex = null;
        factory.setValid(false);
        try {
            obj = pool.borrowObject();
        } catch (Exception e) {
            ex = e;
        }
        // Failure expected
        assertNotNull(ex);
        assertTrue(ex instanceof NoSuchElementException);
        assertNull(obj);

        // Configure factory to create valid objects so subsequent borrows work
        factory.setValid(true);

        // Subsequent borrows should be OK
        try {
            obj = pool.borrowObject();
        } catch (Exception e1) {
            fail();
        }
        assertNotNull(obj);
        try {
            pool.returnObject(obj);
        } catch (Exception e) {
            fail();
        }
    }

    /*
     * Very simple test thread that just tries to borrow an object from
     * the provided pool returns it after a wait
     */
    static class WaitingTestThread extends Thread {
        private final GenericObjectPool<String> _pool;
        private final long _pause;
        private Throwable _thrown;

        private long preborrow; // just before borrow
        private long postborrow; //  borrow returned
        private long postreturn; // after object was returned
        private long ended;
        private String objectId;

        public WaitingTestThread(GenericObjectPool<String> pool, long pause) {
            _pool = pool;
            _pause = pause;
            _thrown = null;
        }

        @Override
        public void run() {
            try {
                preborrow = System.currentTimeMillis();
                String obj = _pool.borrowObject();
                objectId = obj;
                postborrow = System.currentTimeMillis();
                Thread.sleep(_pause);
                _pool.returnObject(obj);
                postreturn = System.currentTimeMillis();
            } catch (Exception e) {
                _thrown = e;
            } finally{
                ended = System.currentTimeMillis();
            }
        }
    }

    private static final boolean DISPLAY_THREAD_DETAILS=
        Boolean.valueOf(System.getProperty("TestGenericObjectPool.display.thread.details", "false")).booleanValue();
    // To pass this to a Maven test, use:
    // mvn test -DargLine="-DTestGenericObjectPool.display.thread.details=true"
    // @see http://jira.codehaus.org/browse/SUREFIRE-121

    /*
     * Test multi-threaded pool access.
     * Multiple threads, but maxTotal only allows half the threads to succeed.
     *
     * This test was prompted by Continuum build failures in the Commons DBCP test case:
     * TestPerUserPoolDataSource.testMultipleThreads2()
     * Let's see if the this fails on Continuum too!
     */
    @Test(timeout=60000)
    public void testMaxWaitMultiThreaded() throws Exception {
        final long maxWait = 500; // wait for connection
        final long holdTime = 2 * maxWait; // how long to hold connection
        final int threads = 10; // number of threads to grab the object initially
        pool.setBlockWhenExhausted(true);
        pool.setMaxWaitMillis(maxWait);
        pool.setMaxTotal(threads);
        // Create enough threads so half the threads will have to wait
        WaitingTestThread wtt[] = new WaitingTestThread[threads * 2];
        for(int i=0; i < wtt.length; i++){
            wtt[i] = new WaitingTestThread(pool,holdTime);
        }
        long origin = System.currentTimeMillis()-1000;
        for(int i=0; i < wtt.length; i++){
            wtt[i].start();
        }
        int failed = 0;
        for(int i=0; i < wtt.length; i++){
            wtt[i].join();
            if (wtt[i]._thrown != null){
                failed++;
            }
        }
        if (DISPLAY_THREAD_DETAILS || wtt.length/2 != failed){
            System.out.println(
                    "MaxWait: " + maxWait +
                    " HoldTime: " + holdTime +
                     " MaxTotal: " + threads +
                    " Threads: " + wtt.length +
                    " Failed: " + failed
                    );
            for(int i=0; i < wtt.length; i++){
                WaitingTestThread wt = wtt[i];
                System.out.println(
                        "Preborrow: " + (wt.preborrow-origin) +
                        " Postborrow: " + (wt.postborrow != 0 ? wt.postborrow-origin : -1) +
                        " BorrowTime: " + (wt.postborrow != 0 ? wt.postborrow-wt.preborrow : -1) +
                        " PostReturn: " + (wt.postreturn != 0 ? wt.postreturn-origin : -1) +
                        " Ended: " + (wt.ended-origin) +
                        " ObjId: " + wt.objectId
                        );
            }
        }
        assertEquals("Expected half the threads to fail",wtt.length/2,failed);
    }

    /**
     * Test the following scenario:
     *   Thread 1 borrows an instance
     *   Thread 2 starts to borrow another instance before thread 1 returns its instance
     *   Thread 1 returns its instance while thread 2 is validating its newly created instance
     * The test verifies that the instance created by Thread 2 is not leaked.
     *
     * @throws Exception May occur in some failure modes
     */
    @Test(timeout=60000)
    public void testMakeConcurrentWithReturn() throws Exception {
        pool.setTestOnBorrow(true);
        factory.setValid(true);
        // Borrow and return an instance, with a short wait
        WaitingTestThread thread1 = new WaitingTestThread(pool, 200);
        thread1.start();
        Thread.sleep(50); // wait for validation to succeed
        // Slow down validation and borrow an instance
        factory.setValidateLatency(400);
        String instance = pool.borrowObject();
        // Now make sure that we have not leaked an instance
        assertEquals(factory.getMakeCounter(), pool.getNumIdle() + 1);
        pool.returnObject(instance);
        assertEquals(factory.getMakeCounter(), pool.getNumIdle());
    }

    /**
     * Ensure the pool is registered.
     */
    @Test(timeout=60000)
    public void testJmxRegistration() {
        ObjectName oname = pool.getJmxName();
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        Set<ObjectName> result = mbs.queryNames(oname, null);
        Assert.assertEquals(1, result.size());
        pool.jmxUnregister();

        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        config.setJmxEnabled(false);
        GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<String>(factory, config);
        assertNull(poolWithoutJmx.getJmxName());
        config.setJmxEnabled(true);
        poolWithoutJmx.jmxUnregister();

        config.setJmxNameBase(null);
        GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<String>(factory, config);
        assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a checked out object is
     * invalidated.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testInvalidateFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(500);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance
        String obj = pool.borrowObject();
        // Launch another thread - will block, but fail in 500 ms
        WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
        thread2.start();
        // Invalidate the object borrowed by this thread - should allow thread2 to create
        Thread.sleep(20);
        pool.invalidateObject(obj);
        Thread.sleep(600); // Wait for thread2 to timeout
        if (thread2._thrown != null) {
            fail(thread2._thrown.toString());
        }
    }

    /**
     * Verify that threads waiting on a depleted pool get served when a returning object fails
     * validation.
     *
     * JIRA: POOL-240
     *
     * @throws Exception May occur in some failure modes
     */
    @Test
    public void testValidationFailureOnReturnFreesCapacity()
        throws Exception {
        SimpleFactory factory = new SimpleFactory();
        factory.setValid(false); // Validate will always fail
        factory.setValidationEnabled(true);
        GenericObjectPool<String> pool = new GenericObjectPool<String>(factory);
        pool.setMaxTotal(2);
        pool.setMaxWaitMillis(1500);
        pool.setTestOnReturn(true);
        pool.setTestOnBorrow(false);
        // Borrow an instance and hold if for 5 seconds
        WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
        thread1.start();
        // Borrow another instance and return it after 500 ms (validation will fail)
        WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
        thread2.start();
        Thread.sleep(50);
        // Try to borrow an object
        String obj = pool.borrowObject();
        pool.returnObject(obj);
    }

    @Test
    public void testSwallowedExceptionListener() {
        pool.setSwallowedExceptionListener(null); // must simply return
        final List<Exception> swallowedExceptions = new ArrayList<Exception>();
        /*
         * A simple listener, that will throw a OOM on 3rd exception.
         */
        final SwallowedExceptionListener listener = new SwallowedExceptionListener() {
            @Override
            public void onSwallowException(Exception e) {
                if (swallowedExceptions.size() == 2) {
                    throw new OutOfMemoryError();
                } else {
                    swallowedExceptions.add(e);
                }
            }
        };
        pool.setSwallowedExceptionListener(listener);

        Exception e1 = new Exception();
        Exception e2 = new ArrayIndexOutOfBoundsException();

        pool.swallowException(e1);
        pool.swallowException(e2);

        try {
            pool.swallowException(e1);
            fail("Not supposed to get here");
        } catch (OutOfMemoryError oom) {
            // expected
        }

        assertEquals(2, swallowedExceptions.size());
    }

    // POOL-248
    @Test(expected=IllegalStateException.class)
    public void testMultipleReturnOfSameObject() throws Exception {
        final GenericObjectPool<String> pool = new GenericObjectPool<String>(
                factory, new GenericObjectPoolConfig());

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        String obj = pool.borrowObject();

        Assert.assertEquals(1, pool.getNumActive());
        Assert.assertEquals(0, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());

        pool.returnObject(obj);

        Assert.assertEquals(0, pool.getNumActive());
        Assert.assertEquals(1, pool.getNumIdle());
    }

    private static final class DummyFactory
            extends BasePooledObjectFactory<Object> {
        @Override
        public Object create() throws Exception {
            return null;
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }
    }


    private static class InvalidFactory
            extends BasePooledObjectFactory<Object> {

        @Override
        public Object create() throws Exception {
            return new Object();
        }
        @Override
        public PooledObject<Object> wrap(Object value) {
            return new DefaultPooledObject<Object>(value);
        }

        @Override
        public boolean validateObject(PooledObject<Object> obj) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // Ignore
            }
            return false;
        }
    }

    private static class EvictionThread<T> extends Thread {

        private final GenericObjectPool<T> pool;

        public EvictionThread(GenericObjectPool<T> pool) {
            this.pool = pool;
        }

        @Override
        public void run() {
            try {
                pool.evict();
            } catch (Exception e) {
                // Ignore
            }
        }
    }
}

Not sure of the meaning you are inferring with 'multiplexed'

Best of Luck in Brasil
Martin 
______________________________________________ 
 _____ _          _____             _          _____     ___ _                        _____               _     _   _         
|_   _| |_ ___   |  _  |___ ___ ___| |_ ___   |   __|___|  _| |_ _ _ _ ___ ___ ___   |   __|___ _ _ ___ _| |___| |_|_|___ ___ 
  | | |   | -_|  |     | . | .'|  _|   | -_|  |__   | . |  _|  _| | | | .'|  _| -_|  |   __| . | | |   | . | .'|  _| | . |   |
  |_| |_|_|___|  |__|__|  _|__,|___|_|_|___|  |_____|___|_| |_| |_____|__,|_| |___|  |__|  |___|___|_|_|___|__,|_| |_|___|_|_|
                       |_|                                                                                                    


From: JLeskovar@telecomsys.com
To: user@commons.apache.org
Subject: Multiplexed connections in commons pool
Date: Wed, 18 Jun 2014 23:07:44 +0000









Hi there,
 
I have an application that needs to perform connection pooling, with the proviso that it's okay - and actually preferable - for more than one client to checkout and use the same connection object from the pool. Ideally, I would also like
 to limit the number of concurrent clients that are using a single connection object. I'm wondering what the best way to do this is. As a quick and dirty option, I suppose I could basically have my PooledObjectFactory return the same objects from makeObject(),
 and manually keep track of objects from inside my implementation. Thoughts?
 
Cheers,
James Leskovar

Software Engineer, Location Platforms
TeleCommunication Systems, Inc.



[ Address : TCS, iC Enterprise 1, Innovation Campus, Squires Way, Nth Wollongong, NSW, 2500, Australia ]

[ Tel : +61 2 4221 2940 ] [ Fax : +61 2 4221 2901 ] 

[ Email : James.Leskovar@telecomsys.com ]

 

CONFIDENTIALITY NOTICE: The information contained in this message may be privileged and/or confidential. If you are not the intended recipient, or responsible for delivering this message to the intended recipient, any review, forwarding, dissemination, distribution or copying of this communication or any attachment(s) is strictly prohibited. If you have received this message in error, please notify the sender immediately, and delete it and all attachments from your computer and network.
 		 	   		  

Re: Multiplexed connections in commons pool

Posted by Phil Steitz <ph...@gmail.com>.
On 6/19/14, 2:36 PM, James Leskovar wrote:
> Hi Phil,
>
> Thanks for the reply. I'll try my hand first at the Pair<Conn,Int> approach, and if it looks workable I can open up a Jira issue.

Great!  Feel free to ask questions if things don't fall into place
easily. 

Phil
>
> Cheers,
> James
>
>
> -----Original Message-----
> From: Phil Steitz [mailto:phil.steitz@gmail.com] 
> Sent: Thursday, 19 June 2014 12:24 PM
> To: Commons Users List
> Subject: Re: Multiplexed connections in commons pool
>
> On 6/18/14, 4:07 PM, James Leskovar wrote:
>> Hi there,
>>
>>  
>>
>> I have an application that needs to perform connection pooling, with 
>> the proviso that it's okay - and actually preferable - for more than 
>> one client to checkout and use the same connection object from the 
>> pool. Ideally, I would also like to limit the number of concurrent 
>> clients that are using a single connection object. I'm wondering what 
>> the best way to do this is. As a quick and dirty option, I suppose I 
>> could basically have my PooledObjectFactory return the same objects 
>> from makeObject(), and manually keep track of objects from inside my 
>> implementation.
>> Thoughts?
>>
> This is an interesting use case that unfortunately is that easy to support in [pool].  If you are interested in helping design and implement direct support, please feel free to hop over to the dev list and open a JIRA.
>
> Your idea of just having the factory return identical instances won't work because when clients return them, they will get exceptions because repeated returns of the same object violates the
> pool contract.   You can make that approach work though by having
> your factory source <Foo, int> pairs where Foo is what you want to pool.  Just make sure the FooInt instances are distinguishable by equals.  Unfortunately, your factory will have to maintain counters, which it can do via the lifecycle methods and probably a hashmap keyed on the actual Foo instances with rep counts as values.
>
> Phil
>>  
>>
>> Cheers,
>>
>> *James Leskovar*
>> Software Engineer, Location Platforms
>>
>> TeleCommunication Systems, Inc.
>>
>> [ *Address* : TCS, iC Enterprise 1, Innovation Campus, Squires Way, 
>> Nth Wollongong, NSW, 2500, Australia ] [ *Tel* : +61 2 4221 2940 ] [ 
>> *Fax* : +61 2 4221 2901 ] [ *Email* : James.Leskovar@telecomsys.com 
>> <ma...@telecomsys.com> ]
>>
>> TCS <http://www.telecomsys.com/default.aspx>Facebook
>> <https://www.facebook.com/pages/TCS/340389379402958>Twitter
>> <https://twitter.com/TeleComSys>LinkedIn
>> <http://www.linkedin.com/company/telecommunication-systems>
>>
>>  
>>
>> CONFIDENTIALITY NOTICE: The information contained in this message may 
>> be privileged and/or confidential. If you are not the intended 
>> recipient, or responsible for delivering this message to the intended 
>> recipient, any review, forwarding, dissemination, distribution or 
>> copying of this communication or any attachment(s) is strictly 
>> prohibited. If you have received this message in error, please notify 
>> the sender immediately, and delete it and all attachments from your 
>> computer and network.
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
> For additional commands, e-mail: user-help@commons.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
> For additional commands, e-mail: user-help@commons.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


RE: Multiplexed connections in commons pool

Posted by James Leskovar <JL...@telecomsys.com>.
Hi Phil,

Thanks for the reply. I'll try my hand first at the Pair<Conn,Int> approach, and if it looks workable I can open up a Jira issue.

Cheers,
James


-----Original Message-----
From: Phil Steitz [mailto:phil.steitz@gmail.com] 
Sent: Thursday, 19 June 2014 12:24 PM
To: Commons Users List
Subject: Re: Multiplexed connections in commons pool

On 6/18/14, 4:07 PM, James Leskovar wrote:
>
> Hi there,
>
>  
>
> I have an application that needs to perform connection pooling, with 
> the proviso that it's okay - and actually preferable - for more than 
> one client to checkout and use the same connection object from the 
> pool. Ideally, I would also like to limit the number of concurrent 
> clients that are using a single connection object. I'm wondering what 
> the best way to do this is. As a quick and dirty option, I suppose I 
> could basically have my PooledObjectFactory return the same objects 
> from makeObject(), and manually keep track of objects from inside my 
> implementation.
> Thoughts?
>

This is an interesting use case that unfortunately is that easy to support in [pool].  If you are interested in helping design and implement direct support, please feel free to hop over to the dev list and open a JIRA.

Your idea of just having the factory return identical instances won't work because when clients return them, they will get exceptions because repeated returns of the same object violates the
pool contract.   You can make that approach work though by having
your factory source <Foo, int> pairs where Foo is what you want to pool.  Just make sure the FooInt instances are distinguishable by equals.  Unfortunately, your factory will have to maintain counters, which it can do via the lifecycle methods and probably a hashmap keyed on the actual Foo instances with rep counts as values.

Phil
>
>  
>
> Cheers,
>
> *James Leskovar*
> Software Engineer, Location Platforms
>
> TeleCommunication Systems, Inc.
>
> [ *Address* : TCS, iC Enterprise 1, Innovation Campus, Squires Way, 
> Nth Wollongong, NSW, 2500, Australia ] [ *Tel* : +61 2 4221 2940 ] [ 
> *Fax* : +61 2 4221 2901 ] [ *Email* : James.Leskovar@telecomsys.com 
> <ma...@telecomsys.com> ]
>
> TCS <http://www.telecomsys.com/default.aspx>Facebook
> <https://www.facebook.com/pages/TCS/340389379402958>Twitter
> <https://twitter.com/TeleComSys>LinkedIn
> <http://www.linkedin.com/company/telecommunication-systems>
>
>  
>
> CONFIDENTIALITY NOTICE: The information contained in this message may 
> be privileged and/or confidential. If you are not the intended 
> recipient, or responsible for delivering this message to the intended 
> recipient, any review, forwarding, dissemination, distribution or 
> copying of this communication or any attachment(s) is strictly 
> prohibited. If you have received this message in error, please notify 
> the sender immediately, and delete it and all attachments from your 
> computer and network.
>


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Re: Multiplexed connections in commons pool

Posted by Phil Steitz <ph...@gmail.com>.
On 6/18/14, 4:07 PM, James Leskovar wrote:
>
> Hi there,
>
>  
>
> I have an application that needs to perform connection pooling,
> with the proviso that it's okay - and actually preferable - for
> more than one client to checkout and use the same connection
> object from the pool. Ideally, I would also like to limit the
> number of concurrent clients that are using a single connection
> object. I'm wondering what the best way to do this is. As a quick
> and dirty option, I suppose I could basically have my
> PooledObjectFactory return the same objects from makeObject(), and
> manually keep track of objects from inside my implementation.
> Thoughts?
>

This is an interesting use case that unfortunately is that easy to
support in [pool].  If you are interested in helping design and
implement direct support, please feel free to hop over to the dev
list and open a JIRA.

Your idea of just having the factory return identical instances
won't work because when clients return them, they will get
exceptions because repeated returns of the same object violates the
pool contract.   You can make that approach work though by having
your factory source <Foo, int> pairs where Foo is what you want to
pool.  Just make sure the FooInt instances are distinguishable by
equals.  Unfortunately, your factory will have to maintain counters,
which it can do via the lifecycle methods and probably a hashmap
keyed on the actual Foo instances with rep counts as values.

Phil
>
>  
>
> Cheers,
>
> *James Leskovar*
> Software Engineer, Location Platforms
>
> TeleCommunication Systems, Inc.
>
> [ *Address* : TCS, iC Enterprise 1, Innovation Campus, Squires
> Way, Nth Wollongong, NSW, 2500, Australia ]
> [ *Tel* : +61 2 4221 2940 ] [ *Fax* : +61 2 4221 2901 ] 
> [ *Email* : James.Leskovar@telecomsys.com
> <ma...@telecomsys.com> ]
>
> TCS <http://www.telecomsys.com/default.aspx>Facebook
> <https://www.facebook.com/pages/TCS/340389379402958>Twitter
> <https://twitter.com/TeleComSys>LinkedIn
> <http://www.linkedin.com/company/telecommunication-systems>
>
>  
>
> CONFIDENTIALITY NOTICE: The information contained in this message
> may be privileged and/or confidential. If you are not the intended
> recipient, or responsible for delivering this message to the
> intended recipient, any review, forwarding, dissemination,
> distribution or copying of this communication or any attachment(s)
> is strictly prohibited. If you have received this message in
> error, please notify the sender immediately, and delete it and all
> attachments from your computer and network.
>


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org