You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/03/13 18:03:42 UTC

[commons-pool] branch master updated: [POOL-362] Always null out org.apache.commons.pool2.impl.BaseGenericObjectPool.evictionIterator to match org.apache.commons.pool2.impl.BaseGenericObjectPool.evictor

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-pool.git


The following commit(s) were added to refs/heads/master by this push:
     new 0187574  [POOL-362] Always null out org.apache.commons.pool2.impl.BaseGenericObjectPool.evictionIterator to match org.apache.commons.pool2.impl.BaseGenericObjectPool.evictor
0187574 is described below

commit 0187574e9cca3ed8c07a989714da922b9697b9a0
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Mar 13 14:03:39 2019 -0400

    [POOL-362] Always null out
    org.apache.commons.pool2.impl.BaseGenericObjectPool.evictionIterator to
    match org.apache.commons.pool2.impl.BaseGenericObjectPool.evictor
---
 src/changes/changes.xml                            | 1559 +++++------
 .../commons/pool2/impl/BaseGenericObjectPool.java  | 2824 ++++++++++----------
 .../apache/commons/pool2/impl/EvictionTimer.java   |  268 +-
 3 files changed, 2328 insertions(+), 2323 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1743a9e..08966f1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -1,777 +1,782 @@
-<?xml version="1.0"?>
-<!--
-     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.
-  -->
-
-<!--
-This file is also used by the maven-changes-plugin to generate the release notes.
-Useful ways of finding items to add to this file are:
-
-1.  Add items when you fix a bug or add a feature (this makes the 
-release process easy :-).
-
-2.  Do a JIRA search for tickets closed since the previous release.
-
-3.  Use the report generated by the maven-changelog-plugin to see all
-SVN commits. TBA how to use this with SVN.
-
-To generate the release notes from this file:
-
-mvn changes:announcement-generate -Prelease-notes [-Dchanges.version=nnn]
-
-then tweak the formatting if necessary 
-and commit
-
-The <action> type attribute can be add,update,fix,remove.
--->
-
-<document>
-  <properties>
-    <title>Apache Commons Pool Changes</title>
-  </properties>
-  <body>
-  <release version="2.6.1" date="2019-02-08" description="This is a maintenance release.">
-    <action dev="struberg" issue="POOL-340" type="fix" due-to="Pavel Kolesov">
-      Correct validateObject with concurrent borrowObject
-    </action>
-    <action dev="struberg" issue="POOL-356" type="fix">
-      Fix deadlock on massive concurrent requests
-    </action>
-    <action dev="ggregory" issue="POOL-345" type="update">
-      Update optional library cglib from 3.2.6 to 3.2.9.
-    </action>
-    <action dev="ggregory" issue="POOL-346" type="update" due-to="Michael Chen">
-      Move common configuration setter to BaseGenericObjectPool #9.
-    </action>
-    <action dev="ggregory" issue="POOL-347" type="fix" due-to="Shunsuke Nakamura">
-      Method borrowObject waits for maxWaitMillis over in pool full.
-    </action>
-    <action dev="ggregory" issue="POOL-349" type="update">
-      Update optional library asm-util from 6.2 to 7.0.
-    </action>
-    <action dev="ggregory" issue="POOL-359" type="fix" due-to="Michael Wintermeyer, Gary Gregory">
-      NullPointerException closing multiple GenericObjectPools.
-    </action>
-    <action dev="ggregory" issue="POOL-360" type="update">
-      Update optional library cglib from 3.2.9 to 3.2.10.
-    </action>
-    <action dev="ggregory" issue="POOL-326" type="fix" due-to="Chris Allison, Phil Steitz">
-      Threading issue, NullPointerException and IllegalStateException in GenericKeyedObjectPool.
-    </action>
-    <action dev="ggregory" issue="POOL-352" type="fix" due-to="Volker Kleinschmidt, Gary Gregory">
-      CallStackUtils mishandles security manager check (partial fix.)
-    </action>
-  </release>  
-  <release version="2.6.0" date="2018-07-06" description="This is a maintenance release.">
-    <action dev="ggregory" issue="POOL-336" type="update" due-to="Wolfgang Glas">
-      GenericObjectPool's borrowObject lock if create() fails with Error.
-    </action>
-    <action dev="ggregory" issue="POOL-339" type="update">
-      Update optional library cglib from 3.2.5 to 3.2.6.
-    </action>
-    <action dev="markt" issue="POOL-337" type="fix" due-to="Reinald Verheij">
-      Ensure cancelled eviction tasks are removed from scheduler.
-    </action>
-    <action dev="ggregory" issue="POOL-341" type="update">
-      Update optional library asm-util from 6.0 to 6.1.1.
-    </action>
-    <action dev="ggregory" issue="POOL-342" type="update">
-      Update optional library asm-util from 6.1.1 to 6.2.
-    </action>
-    <action dev="ggregory" issue="POOL-338" type="fix" due-to="Michael C, Gary Gregory">
-      GenericObjectPool constructor may throw an exception under OSGi.
-    </action>
-    <action dev="ggregory" issue="POOL-324" type="fix" due-to="Jay Xu, Gary Gregory">
-      org.apache.commons.pool2.impl.GenericObjectPool.getFactoryType() throws java.lang.ClassCastException.
-    </action>
-    <action dev="ggregory" issue="POOL-344" type="fix" due-to="Yulin Wang">
-      Delete repeated call startEvictor.
-    </action>
-  </release>
-  <release version="2.5.0" date="2017-12-16" description="This is a minor release, updating to Java 7.">
-    <action dev="ggregory" issue="POOL-331" type="update">
-      Update from Java 6 to 7.
-    </action>
-    <action dev="ggregory" issue="POOL-330" type="delete">
-      Drop Ant build.
-    </action>
-    <action dev="ggregory" issue="POOL-332" type="add">
-      ObjectPool and KeyedObject pool should extend Closeable.
-    </action>
-    <action dev="ggregory" issue="POOL-333" type="update">
-      Update optional dependency asm-util from 5.2 to 6.0.
-    </action>
-    <action dev="ggregory" issue="POOL-334" type="update">
-      org.apache.commons.pool2.impl.ThrowableCallStack.Snapshot is missing serialVersionUID.
-    </action>
-    <action dev="mattsicker" issue="POOL-335" type="add">
-      Make abandoned logging stack trace requirements configurable. This also reverts
-      the default behavior introduced by POOL-320.
-    </action>
-    <action dev="mattsicker" issue="POOL-335" type="add">
-      Make abandoned logging stack trace requirements configurable. This also reverts
-      the default behavior introduced by POOL-320.
-    </action>
-  </release>
-  <release version="2.4.3" date="2017-10-24" description="This is a patch release, including bug fixes only.">
-    <action dev="ggregory" issue="POOL-328" type="fix" due-to="Lorenzo Solano Martinez">
-      Documentation with repeated words (sources, tests, and examples).
-    </action>
-    <action dev="ggregory" issue="POOL-317" type="fix" due-to="KeiichiFujino">
-      Correction of default value of softMinEvictableIdleTimeMillis in BaseObjectPoolConfig.
-    </action>
-    <action dev="ggregory" issue="POOL-309" type="fix" due-to="jolestar, Roopam Patekar">
-      Fix misspellings from "destory" to "destroy".
-    </action>
-    <action dev="markt" issue="POOL-306" type="fix" due-to="Adrian Crum">
-      Ensure BaseGenericObjectPool.IdentityWrapper#equals() follows the expected
-      contract for equals(). 
-    </action>
-    <action dev="markt" issue="POOL-303" type="fix">
-      Ensure that threads do not block indefinitely if more than maxTotal
-      threads try to borrow an object at the same time and the factory fails to
-      create any objects. 
-    </action>
-    <action dev="markt" issue="POOL-280" type="update" due-to="Jacopo Cappellato">
-      Small refactoring of borrowObject() to reduce code duplication.
-    </action>
-    <action dev="markt" issue="POOL-307" type="update" due-to="Anthony Whitford">
-      Replace inefficient use of keySet with entrySet in GKOP.
-    </action>
-    <action dev="markt" issue="POOL-310" type="fix" due-to="Ivan Iliev">
-      Ensure that threads using GKOP do not block indefinitely if more than
-      maxTotal threads try to borrow objects with different keys at the same
-      time and the factory destroys objects on return. 
-    </action>
-    <action dev="markt" type="fix">
-      Ensure that any class name used for evictionPolicyClassName represents a
-      class that implements EvictionPolicy.
-    </action>
-    <action dev="markt" issue="POOL-315" type="fix" due-to="KeiichiFujino">
-      Add a configurable delay (default 10 seconds) to wait when shutting down
-      an Evictor to allow the associated thread time to complete any current
-      evictions and to terminate.
-    </action>
-    <action dev="markt" type="fix">
-      Ensure that a call to GKOP preparePool() takes account of other threads
-      that might create objects concurrently, particularly the Evictor.
-    </action>
-    <action dev="mattsicker" issue="POOL-320" type="add">
-      Use more efficient stack walking mechanisms for usage tracking when possible.
-    </action>
-    <action dev="ggregory" issue="POOL-322" type="update">
-      Update optional cglib library from 3.1 to 3.2.5.
-    </action>
-    <action dev="ggregory" issue="POOL-323" type="update">
-      Update optional OW2 ASM from 5.0.4 to 5.2.
-    </action>
-  </release>
-  <release version="2.4.2" date="2015-08-01" description=
- "This is a patch release, including bug fixes only.">
-    <action dev="psteitz" issue="POOL-298" type="fix">
-      Changed default jmxNameBase in BaseObjectPoolConfig to the correct (null)
-      default.
-    </action>
-    <action dev="psteitz" issue="POOL-300" type="fix">
-      Added PrintWriter flush to DefaultPooledObject's printStackTrace method.
-    </action>
-  </release>
-  <release version="2.4.1" date="2015-05-30" description=
- "This is a patch release, replacing a defective binary jar in version 2.4. Other
-than the build configuration, the source distribution for version 2.4.1 is identical
-to version 2.4.">
-    <action dev="psteitz" issue="POOL-297" type="fix">
-      Reverted cobertura plugin update that caused binary jar corruption.
-    </action>
-  </release>
-  <release version="2.4" date="2015-05-27" description=
- "This is a maintenance release that includes bug fixes and minor enhancements.">
-    <action dev="psteitz" type="fix" issue="POOL-287" due-to="Caleb Spare and Thomas Neidhart">
-      Fixed capacity leak when an object is offered from a GenericKeyedObjectPool while it is
-      being validated by the evictor. 
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-283">
-      Eliminated the requirement that objects managed by GenericObjectPool or
-      GenericKeyedObjectPool be discernible by equals.  Prior to this fix,
-      equal but distinct object instances could not be stored in the same pool.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-284">
-      Eliminated the requirement that object equality and hashcodes do not change
-      while objects are under management by GenericObjectPool or GenericKeyedObjectPool.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-289" due-to="Luke Winkenbach">
-      Fixed class loading for custom EvictionPolicy implementations that may not
-      be present in the class loader hierarchy of the Pool classes by falling
-      back to the class loader of the current class.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-285">
-      Ensured that when an instance that has already been returned to a pool is
-      returned again, the expected IllegalStateException is generated before the
-      returning object is re-validated or re-passivated.
-    </action>
-    <action dev="psteitz" type="add" issue="POOL-286">
-      Added preparePool method to GenericObjectPool.
-    </action>
-    <action dev="ggregory" type="update" issue="POOL-296">
-      Update asm-util from 5.0.3 to 5.0.4.
-    </action>
-    <action dev="psteitz" type="update" issue="POOL-293">
-      Exposed getEvictionPolicy as protected in BaseGenericObjectPool.
-    </action>
-  </release>
-  <release version="2.3" date="2014-12-30" description=
-"This is a maintenance release that includes bug fixes and minor enhancements.">  
-    <action dev="psteitz" type="fix" issue="POOL-279" due-to="Jacopo Cappellato">
-      Eliminated possibility that DefaultPoolObject#getIdleTimeMillis() could
-      return a negative value. Use by pool implementations would not hit this
-      bug. 
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-275">
-      Made wrapped BaseProxyHandler.pooledObject volatile.
-    </action>
-    <action dev="ecki" type="fix" issue="POOL-277" due-to="Lucas Pouzac">
-      Replace synchronisation with lock-free maxBorrowWaitTimeMillis to
-      increase scalability.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-276">
-      Ensure that objects are not validated on borrow when testOnBorrow is set
-      to false, testOnCreate is set to true and the pool is exhausted at the
-      point borrowObject() is called.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-270" due-to="Michael Berman">
-      Fixed error in GenericKeyedObjectPool constructor causing minEvictableIdleTimeMillis
-      to be used in place of timeBetweenEvictionRunsMillis in eviction timer setup
-      when a GenericKeyedObjectPoolConfig instance is supplied to the constructor.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-263">
-      Fix a threading issue that meant that concurrent calls to close() and
-      returnObject() could result in some returned objects not being destroyed.
-    </action>
-    <action dev="psteitz" type="add" issue="POOL-262">
-      Made fairness configurable for GenericObjectPool, GenericKeyedObjectPool.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-261">
-      Correctly mark cglib as an optional dependency and ensure that the OSGi
-      manifest information reflects that.
-    </action>
-    <action dev="markt" type="fix">
-      Improve performance of statistics collection for pools that extend
-      BaseGenericObjectPool.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-259">
-      Made client wait time statistics accurate when pools are configured to
-      block indefinitely.  Also modified computation to include latency clients
-      experience due to waiting on factory methods.
-    </action>
-    <action dev="ggregory" type="update" issue="POOL-273">
-      Update cglib to 3.1 from 3.0.
-    </action>
-    <action dev="ggregory" type="update" issue="POOL-274">
-      Update asm-util to 5.0.3 from 4.0.
-    </action>
-    <action dev="markt" type="fix">
-      Prevent potential memory leaks when the Pool is dereferenced without being
-      closed.
-    </action>
-    <action dev="markt" type="fix">
-      Prevent potential memory leaks with using an Evictor in a container
-      environment.
-    </action>
-    <action dev="markt" type="fix">
-      Protect against a user provided eviction policy throwing an exception and
-      stopping the Evictor thread.
-    </action>
-    <action dev="markt" type="fix">
-      Use the thread context class loader to load custom eviction policies. This
-      allows application provided eviction policies to be used in a container
-      environment when the pooling implementation is provided by the container.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-281">
-      Fix a potential infinite loop in the underlying Deque implementation.
-    </action>
-  </release>
-  <release version="2.2" date="2014-02-24" description=
-"This is a maintenance release that adds a new testOnCreate configuration option
-and fixes a small number of bugs.">
-    <action issue="POOL-248" dev="markt" type="fix" due-to="Warren Chen">
-      Ensure that if an attempt is made to return an object multiple times that
-      the current active and idle object counts are not corrupted.
-    </action>
-    <action issue="POOL-249" dev="markt" type="fix" due-to="Ville Skyttä">
-      Fix Javadoc issues when building docs with Java 8.
-    </action>
-    <action dev="markt" type="fix">
-      Fix the remaining Javadoc warnings.
-    </action>
-    <action dev="markt" type="add">
-      Add a new validation configuration option testOnCreate that tests an
-      object immediately after it is created.
-    </action>
-  </release>
-   <release version="2.1" date="2013-12-30" description=
-"This is a maintenance release that includes a small number of new features as well as 
-including bugfixes and test case improvements.">
-    <action issue="POOL-243" dev="psteitz" type="fix" due-to="Michal Sabo">
-      Added missing create counter decrement in GenericKeyedObjectPool create method on factory
-      exception path. Prior to this fix, exceptions thrown by factory makeObject calls could leak
-      per key capacity.
-    </action>
-    <action issue="POOL-240" dev="psteitz" type="fix" due-to="Dan McNulty">
-      Ensured that blocked threads waiting on a depleted pool get served when
-      objects are destroyed due to validation or passivation failures in
-      returnObject or when a checked out instance is invalidated.
-    </action>
-    <action issue="POOL-241" dev="markt" type="add" due-to="Bruno P. Kinoshita">
-      Expand the coverage of the unit tests.
-    </action>
-    <action dev="markt" type="add">
-      Provide more control over the names under which Pools are registered in
-      JMX so components using the pools can register the pools they use under a
-      related name.
-    </action>
-    <action dev="markt" type="add">
-      Include the number of times an object has been borrowed from the Pool when
-      the DefaultPooledObject wrapper is used and expose this property via JMX.
-    </action>
-    <action issue="POOL-245" dev="markt" type="fix" due-to="Bruno P. Kinoshita">
-      Remove a duplicate null check and fix some typos in PoolUtils.
-    </action>
-    <action issue="POOL-246" dev="markt" type="fix" due-to="Bruno P. Kinoshita">
-      Make the toString() method of ErodingKeyedObjectPool consistent with the
-      other pools.
-    </action>
-    <action issue="POOL-245" dev="markt" type="add" due-to="Bruno P. Kinoshita">
-      Further expansion of the coverage of the unit tests.
-    </action>
-  </release>
-  <release version="2.0" date="2013-11-11" description=
-"This is a major new release that provides significant performance improvements
-in high concurrency environments. Pools now provide a mechanism for tracking
-objects that have been borrowed from the pool but not returned. There have been
-numerous API changes to support these and other new features as well as to
-clarify behaviour and improve consistency across the API. This release requires
-JDK level 1.6 or above.">
-    <action issue="POOL-211" dev="markt" type="add" due-to="Brad Koehn">
-      Add support for proxy wrappers to ObjectPool and KeyedObjectPool. The
-      primary advantage of these wrappers is that use of pooled objects is
-      prevented after they have been returned to the pool.
-    </action>
-    <action issue="POOL-229" dev="psteitz" type="update">
-      Added abandoned object removal (moved from DBCP) to GenericObjectPool.
-    </action>
-    <action issue="POOL-221" dev="markt" type="fix" >
-      PooledObject.state does not need to be volatile
-    </action>
-    <action issue="POOL-220" dev="markt" type="fix">
-      Suppress a FindBugs warning
-    </action>
-    <action issue="POOL-217" dev="markt" type="update"  due-to="sebb">
-      Use an IODH for PoolUtils.MIN_IDLE_TIMER
-    </action>
-    <action issue="POOL-216" dev="markt" type="update" >
-      GenericKeyedObjectPool.ensureMinIdle(K) does not need to check getMinIdlePerKey().
-    </action>
-    <action issue="POOL-215" dev="markt" type="fix" >
-      GenericKeyedObjectPool - multiple mutable fields not published safely.
-    </action>
-    <action issue="POOL-214" dev="markt" type="fix" >
-      GenericObjectPool.evictionPolicy not thread-safe
-    </action>
-    <action issue="POOL-212" dev="markt" type="fix" >
-      GenericObjectPool allows maxIdle &lt; minIdle
-    </action>
-    <action issue="POOL-207" dev="markt" type="fix" >
-      GenericKeyedObjectPool.clear() has unnecessary null check of objectDequeue
-    </action>
-    <action issue="POOL-201" dev="markt" type="fix" >
-      Classes Generic[Keyed]ObjectPoolConfig are generic - but why? 
-    </action>
-    <action issue="POOL-200" dev="markt" type="fix" >
-      GOP/GKOP don't consistently use getters to access fields
-    </action>
-    <action issue="POOL-199" dev="markt" type="fix" >
-      GOP/GKOP evict() method is not synchronised and is not thread-safe
-    </action>
-    <action issue="POOL-197" dev="markt" type="fix" >
-      PooledObject: risky init of lastBorrowTime &amp; lastReturnTime
-    </action>
-    <action issue="POOL-196" dev="markt" type="fix" >
-      PooledObject.getActiveTimeMillis() does not synch. access to lastReturnTime and lastBorrowTime
-    </action>
-    <action issue="POOL-194" dev="simonetripodi" type="update" date="2011-12-12">
-      Replace synchronized blocks in PoolUtils with Read/Write locks.
-    </action>
-    <action issue="POOL-83" dev="simonetripodi" type="update" date="2011-04-28">
-      Support Java 1.5 Generics.
-    </action>
-    <action issue="POOL-186" dev="simonetripodi" type="update" date="2011-04-28">
-      Developer documentation and examples have to be updated once the 2.0 repackaging has been done
-    </action>
-    <action dev="markt" type="update">
-      Switch GOP to use a pooling mechanism based on java.util.concurrent and a
-      LinkedBlockingQueue implementation from Apache Harmony (originally by Doug
-      Lea and the JSR-166 expert group).
-    </action>
-    <action dev="markt" type="update">
-      Make deprecated protected attributes private, requiring that access is via
-      the appropriate getters. 
-    </action>
-    <action dev="markt" type="update">
-      Code clean-up. Add missing @Override annotations, remove unused code,
-      remove deprecated code and unnecessary code.
-    </action>
-    <action dev="markt" type="update">
-      Introduce an Enum (WhenExhaustedAction) to control pool behaviour when no
-      more objects are available to allocate.
-    </action>
-    <action dev="markt" type="update">
-      Remove WhenExhuastedAction.GROW since it is equivalent to
-      WhenExhuastedAction.FAIL with a maxActive value of Integer.MAX_VALUE. 
-    </action>
-    <action issue="POOL-188" dev="markt" type="fix" due-to="sebb">
-      Remove confusing method PoolUtils.ErodingKeyedObjectPool.numIdle(K key).
-    </action>
-    <action issue="POOL-155" dev="markt" type="update">
-      Guard against multiple returns of the same object to the pool and ensure
-      that only objects borrowed from the pool are returned to it.
-    </action>
-    <action issue="POOL-150" dev="markt" type="fix">
-      Ensure GKOP.preparePool() throws an exception if no factory has been
-      defined.
-    </action>
-    <action issue="POOL-134" dev="markt" type="fix">
-      Add the ability to specify a per call wait time when borrowing an object.
-    </action>
-    <action issue="POOL-121" dev="markt" type="fix">
-      Provide a name for the eviction timer thread.
-    </action>
-    <action dev="markt" type="update">
-      Remove setFactory() method from GOP.
-    </action>
-    <action issue="POOL-173" dev="markt" type="fix">
-      Reduce duplication in configuration code.
-    </action>
-    <action issue="POOL-178" dev="markt" type="fix">
-      Re-factor common code into common base classes.
-    </action>
-    <action issue="POOL-172" dev="markt" type="update">
-      Expose GOP and GKOP attributes via JMX.
-    </action>
-    <action issue="POOL-98" dev="markt" type="update">
-      Add additional attributes (also accessible via JMX) for monitoring.
-    </action>
-    <action dev="markt" type="update">
-      Change meaning of zero for maxWait to a maximum wait of zero milliseconds
-      rather than the unexpected infinite wait.
-    </action>
-    <action issue="POOL-100" dev="markt" type="fix">
-      Allow custom eviction policies to be defined.
-    </action>
-    <action issue="POOL-211" dev="markt" type="add" due-to="Brad Koehn">
-      Add support for proxy wrappers for ObjectPool and KeyedObjectPool. The
-      primary advantage of using these wrappers is that use of pooled objects
-      is prevented after they have been returned to the pool.  
-    </action>
-  </release>
-  <release version="1.6" date="2012-01-07" description="Adds generics and requires Java 5.">
-    <action dev="ggregory" type="add" issue="POOL-208">
-      Support Java 1.5 Generics in version 1.x.
-    </action>
-  </release>
-  <release version="1.5.7" date="2011-12-20" description="This is a patch release, including bugfixes only.">
-    <action dev="psteitz" type="fix" issue="POOL-189" due-to="Bill Speirs">
-      Awaken threads waiting on borrowObject when a pool has been closed and have them throw
-      IllegalStateException.  Prior to the fix for this issue, threads waiting in borrowObject when
-      close was invoked on GOP or GKOP would block indefinitely.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-192" due-to="Helge Dannenberg">
-      Corrected total internal processing counter update in destroy.  Prior to the fix
-      for this issue, clear(key) was leaking capacity associated with elements in the
-      pool being cleared.
-    </action>
-  </release>
-  <release version="1.5.6" date="2011-04-03" description="This is a patch release, including bugfixes only.">
-    <action dev="markt" type="fix" issue="POOL-179" due-to="Axel Grossmann">
-      Correctly handle an InterruptedException when waiting for an object from
-      the pool.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-180">
-      Only stop tracking objects for a key when there are no idle objects, no
-      active objects and no objects being processed.
-    </action>
-    <action dev="markt" type="update" issue="POOL-181">
-      Make BaseObjectPool.isClosed() public.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-184" due-to="Adrian Nistor">
-      Correct bug that could lead to inappropriate pool starvation when evict()
-      and borrowObject() are called concurrently.
-    </action>
-    <action dev="markt" type="fix" due-to="psteitz">
-      Fix performance issues when object destruction has latency.
-    </action>
-  </release>
-  <release version="1.5.5" date="2010-09-10" description=
-     "This is a patch release, including bugfixes, documentation improvements and some deprecations
-      in preparation for pool 2.0.">
-    <action dev="psteitz" type="update" issue="POOL-169">
-      In preparation for pool 2.0, deprecated direct access to protected fields
-      and setFactory methods.  In pool 2.0, pool object factories will be immutable.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-158">
-      Made GenericKeyedObjectPool._minIdle volatile.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-161">
-      Made the default context class loader for the eviction thread the same loader that loads
-      the library to prevent memory leaks in multiple class loader environments.
-    </action>
-    <action dev="sebb" type="update" issue="POOL-166">
-      GenericKeyedObjectPool.destroy could use entrySet() rather than keySet() followed by get()
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-157" due-to="David Hu">
-      GenericObjectPool and GenericKeyedObjectPool setFactory methods destroy idle instances
-      in the pool by contract. Prior to the fix for this issue, newly set factories were being
-      used to destroy idle instances, rather than the factories used to create them.  The 
-      setFactory methods have also been deprecated, to be removed in version 2.0.
-    </action>
-    <action dev="sebb" type="update" issue="POOL-156">
-      ObjectPool classes can ignore Throwable. Added consistent handling for Throwables
-      that are normally swallowed including always re-throwing certain Throwables (e.g. ThreadDeath).
-    </action>
-    <action dev="markt" type="fix" issue="POOL-162">
-      When waiting threads are interrupted, GOP, GKOP may leak capacity.
-    </action>
-    <action dev="psteitz" type="fix" issue="POOL-154" due-to="Glen Mazza">
-      Documentation for the close method in GenericObjectPool and GenericKeyedObjectPool
-      incorrectly states that this method does not clear the pool.
-    </action>
-  </release>
-  <release version="1.5.4" date="2009-11-20" description=
- "This is a patch release containing a fix for POOL-152, a regression
-introduced in version 1.5.">
-    <action dev="markt" type="fix" issue="POOL-152" due-to="Bushov Alexander">
-      GenericObjectPool can block forever in borrowObject when the pool is exhausted and a newly created
-      object fails validation. When borrowing an object if a new object is created but validate fails,
-      the latch should not be returned to the queue as an exception will be thrown.
-    </action>
-  </release>
-  <release version="1.5.3" date="2009-09-21" description=
-"This is a patch release containing a fix for POOL-149, a regression
-introduced in version 1.5.">
-    <action dev="markt" type="fix" issue="POOL-149" due-to="Shuyang Zhou">
-      Fix case where a thread could end up waiting indefinitely even if objects
-      were available. Also fixes a couple of leaks in the internal processing
-      object count that could lead to pool exhaustion.
-    </action>
-  </release>
-  <release version="1.5.2" date="2009-07-12" description=
-"This is a patch release containing fixes for POOL-146 and POOL-147, regressions
-introduced in version 1.5.">
-    <action dev="markt" type="fix" issue="POOL-146">
-      Handle the case where one key has reached maxActive but other keys have not.
-      Prior to the fix for this issue, threads waiting on objects from keyed pools
-      still having instances available could be blocked by a thread requesting an
-      instance from an exhausted pool.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-147" due-to="Giambattista Bloisi">
-      Fix case where a thread could end up waiting indefinitely even if objects
-      were available.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-145">
-      Ensure that the GenericKeyedObjectPool idle object evictor does not visit the
-      same instance more than once per eviction run.
-    </action>
-  </release>
-  <release version="1.5.1" date="2009-06-16" description=
-"This is a patch release containing a fix for POOL-144, a regression introduced
-in version 1.5.">
-    <action dev="markt" type="fix" issue="POOL-144">
-      When exhausted action is set to WHEN_EXHAUSTED_BLOCK, maxwait is positive and
-      client threads time out waiting for idle objects, capacity can be "leaked"
-      from GenericObjectPools and GeneritCkeyedObjectPools. 
-    </action>
-  </release>
-  <release version="1.5" date="2009-06-10" description=
-"This is a maintenance release including several important bug fixes. This release
-is source and binary compatible with versions 1.3 and 1.4 of commons pool. In addition
-to resolving some important concurrency-related bugs (POOL-135, POOL-125, POOL-29
-POOL-107) this release implements a fairness algorithm to ensure that threads waiting
-for available object instances from GenericObjectPools and GenericKeyedObjectPools are served
-in request arrival order.">
-    <action dev="markt" type="fix" issue="POOL-139" due-to="Sebastian Bazley">
-      StackKeyedObjectPool.getNumActive() needs to be synchronized.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-137" due-to="Sebastian Bazley">
-      Inconsistent synchronization in GenericObjectPool; constant fields should be final.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-75" due-to="Takayuki Kaneko and Gordon Mohr">
-       GenericObjectPool not FIFO with respect to borrowing threads.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-135">
-      _numActive > _maxActive under load
-    </action>
-    <action dev="markt" type="fix" issue="POOL-125">
-      Insufficient control over concurrent access to pooled objects by Evictor, client threads.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-107">
-      Number of connections created has crossed more than maxActive.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-122">
-      java.util.Timer in EvictionTimer does not recover from OutOfMemoryError in Evictor.
-    </action>
-    <action dev="markt" type="fix" issue="POOL-133">
-      Failed object creation may result in invalid active count in GKOP.
-    </action>
-  </release>
-  <release version="1.4" date="2008-01-15" description=
-"This is a maintenance release including numerous bug fixes. This release
-is source and binary compatible with version 1.3 of commons pool, but
-there are some behavior changes introduced to resolve bugs, remove ambiguity
-or improve robustness. Among these are the change in default behavior of
-GenericObjectPool and GenericKeyedObjectPool from FIFO back to LIFO queues
-(as in 1.2 and earlier). The LIFO/FIFO behavior is now configurable. Some of
-the extra synchronization included in version 1.3 was removed / refactored to
-improve performance. The javadoc has also been made more complete and explicit.
-See the detailed list of changes below for specifics on fixed bugs and behavior
-changes in Commons Pool 1.4. This version of Commons Pool depends only on
-JDK version 1.3 or higher. Classes implementing pools are all intended to be
-threadsafe.">
-      <action dev="sandymac" type="fix">
-        Fixed constructor which was ignoring maxTotal parameter: 
-          GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
-          long maxWait, int maxIdle, int maxTotal, boolean testOnBorrow, boolean testOnReturn,
-          long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis,
-          boolean testWhileIdle)
-      </action>
-      <action dev="sandymac" type="fix">
-        Changed StackKeyedObjectPool to discard stalest, not freshest, idle object when maxSleeping is reached.
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-102" due-to="John Sumsion">
-        Allowed blocked threads in GenericObjectPool borrowObject to be interrupted.
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-86">
-        Fixes to address idle object eviction and LIFO/FIFO behavior reported
-        in POOL-86. Made LIFO/FIFO behavior configurable for GenericObjectPool and
-        GenericKeyedObjectPool, with default set back to LIFO (reverting to 1.2 behavior).
-        Fixed GOP, GKOP evict method and added tests to ensure objects are visited in
-        oldest-to-youngest order. Changed backing store for GOP, GKOP pools back to Commons
-        Collections CursorableLinkedList (brought this class in, repackaged with package scope).
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-110" due-to="Alexander Pogrebnyak">
-        Changed the default setting for Config.softMinEvictableIdleTimeMillis to
-        GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS (was
-        being incorrectly defaulted to DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS).
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-97" due-to="Mark Thomas">
-         Added a wrapper for the shared idle object eviction timer for all
-         pools. The wrapper class wraps the Timer and keeps track of how many
-         pools are using it. If no pools are using the timer, it is canceled.
-         This prevents a thread being left running which, in application server
-         environments, can lead to memory leaks and/or prevent applications
-         from shutting down or reloading cleanly.
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-93"  
-      due-to="Mark Thomas">
-        Reduced synchronization in GenericObjectPool, GenericKeyedObjectPool.
-        Factory method activations within synchronized blocks were causing
-        performance problems in DBCP and other applications where factory
-        methods could block. Fixes both POOL-93 and POOL-108.
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-113">
-        Made _testOnBorrow, _testOnReturn volatile and removed synchronization
-        in associated getters and setters in GenericObjectPool,
-        GenericKeyedObjectPool. Made getNumIdle synchronized in
-        StackKeyedObjectPool. 
-      </action>
-      <action dev="psteitz" type="fix" issue="POOL-116">
-        Fixed an error in the GenericKeyedObjectPool constructor that takes
-        a Config instance as a parameter. The minIdle setting in the Config
-        was being ignored by the constructor.
-      </action>
-      <action def="psteitz" type="fix" issue="POOL-117">
-        Made behavior on instance validation failure consistent across pools,
-        eliminating possible infinite loops in StackObjectPool,
-        StackKeyedObjectPool, SoftReferenceObjectPool when factory fails to
-        create valid objects. 
-      </action>
-      <action dev="sandymac" type="update">
-        When no factory has been defined, addObject now throws 
-        IllegalStateExecption instead of NullPointerException for all pools.
-      </action>
-      <action dev="sandymac" type="update">
-        SoftReferenceObjectPool. Improved the accuracy of getNumIdle by
-        "pruning" references to objects that have been garbage collected.
-      </action>
-      <action dev="sandymac" type="update">
-        GenericObjectPool, GenericKeyedObjectPool, SoftReferenceObjectPool,
-        StackObjectPool. Eliminated IllegalStateExceptions when the following
-        operations are attempted on a closed pool: getNumActive, getNumIdle, 
-        returnObject, invalidateObject.  In each case, the operation is allowed
-        to proceed, reporting the state of the pool that is being shut down, or
-        destroying objects returning to the closed pool.
-      </action>
-      <action dev="sandymac" type="update">
-        StackObjectPool, SoftReferenceObjectPool, GenericKeyedObjectPool. Allowed
-        borrowObject to continue (either examining additional idle instances or
-        with makeObject) when an exception is encountered activating an idle
-        object instead of propagating the exception to the client.  Also made
-        addObject propagate (not swallow) exceptions when passivating newly
-        created instances. 
-      </action>
-      <action dev="psteitz" type="update">
-        StackKeyedObjectPool. Added validation check for objects returned
-        from borrowObject. 
-      </action>
-      <action dev="sandymac" type="update">
-        BaseObjectPool, BaseKeyedObjectPool. Instead of throwing 
-        UnsupportedOperationException, the base class implementations
-        of getNumIdle and getNumActive return negative values. The
-        base implementation of close in BaseObjectPool no longer throws
-        IllegalStateException when invoked on an already closed pool.
-      </action>
-      
-    </release>
-
-    <release version="1.3" date="2006-04-06" description="1.x bugfix release">
-      <action type="fix">A large number of bug fixes. See release notes for changes.</action>
-    </release>
-
-    <release version="1.2" date="2004-06-07" description="bugfixes">
-      <action dev="dirkv" type="fix">
-           GenericKeyedObjectPoolFactory Config Constructor is incorrect
-      </action>
-      <action dev="dirkv" type="fix">
-        Not possible to extend GenericObjectPool.returnObject() without affecting addObject()
-      </action>
-    </release>
-
-    <release version="1.1" date="2003-10-20" description="bugfixes">
-      <action type="fix">A lot of corner cases were fixed</action>
-      <action type="fix">Performance improvement by optimizing pool synchronization, the critical code paths were optimized by reducing pool synchronization but we also added more synchronization where needed</action>
-      <action type="fix">New minIdle feature: the minimum number of objects allowed in the pool before the evictor thread (if active) spawns new objects. (Note no objects are created when: numActive + numIdle >= maxActive)</action>
-      <action type="fix">New maxTotal feature: a cap on the total number of instances controlled by a pool. Only for GenericKeyedObjectPool where maxActive is a cap on the number of active instances from the pool (per key).</action>
-      <action type="fix">UML Class and sequence diagrams</action>
-      <action type="fix">See bugzilla for more changes</action>
-    </release>
-
-    <release version="1.0.1" date="2002-08-12">
-      <action type="fix">No change log available.</action>
-    </release>
-
-    <release version="1.0" date="2002-05-04">
-      <action type="add">No change log available.</action>
-    </release>
-  </body>
-</document>
+<?xml version="1.0"?>
+<!--
+     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.
+  -->
+
+<!--
+This file is also used by the maven-changes-plugin to generate the release notes.
+Useful ways of finding items to add to this file are:
+
+1.  Add items when you fix a bug or add a feature (this makes the 
+release process easy :-).
+
+2.  Do a JIRA search for tickets closed since the previous release.
+
+3.  Use the report generated by the maven-changelog-plugin to see all
+SVN commits. TBA how to use this with SVN.
+
+To generate the release notes from this file:
+
+mvn changes:announcement-generate -Prelease-notes [-Dchanges.version=nnn]
+
+then tweak the formatting if necessary 
+and commit
+
+The <action> type attribute can be add,update,fix,remove.
+-->
+
+<document>
+  <properties>
+    <title>Apache Commons Pool Changes</title>
+  </properties>
+  <body>
+  <release version="2.6.2" date="2019-MM-DD" description="This is a maintenance release.">
+    <action dev="ggregory" issue="POOL-362" type="fix">
+       Always null out org.apache.commons.pool2.impl.BaseGenericObjectPool.evictionIterator to match org.apache.commons.pool2.impl.BaseGenericObjectPool.evictor.
+    </action>
+  </release>
+  <release version="2.6.1" date="2019-02-08" description="This is a maintenance release.">
+    <action dev="struberg" issue="POOL-340" type="fix" due-to="Pavel Kolesov">
+      Correct validateObject with concurrent borrowObject
+    </action>
+    <action dev="struberg" issue="POOL-356" type="fix">
+      Fix deadlock on massive concurrent requests
+    </action>
+    <action dev="ggregory" issue="POOL-345" type="update">
+      Update optional library cglib from 3.2.6 to 3.2.9.
+    </action>
+    <action dev="ggregory" issue="POOL-346" type="update" due-to="Michael Chen">
+      Move common configuration setter to BaseGenericObjectPool #9.
+    </action>
+    <action dev="ggregory" issue="POOL-347" type="fix" due-to="Shunsuke Nakamura">
+      Method borrowObject waits for maxWaitMillis over in pool full.
+    </action>
+    <action dev="ggregory" issue="POOL-349" type="update">
+      Update optional library asm-util from 6.2 to 7.0.
+    </action>
+    <action dev="ggregory" issue="POOL-359" type="fix" due-to="Michael Wintermeyer, Gary Gregory">
+      NullPointerException closing multiple GenericObjectPools.
+    </action>
+    <action dev="ggregory" issue="POOL-360" type="update">
+      Update optional library cglib from 3.2.9 to 3.2.10.
+    </action>
+    <action dev="ggregory" issue="POOL-326" type="fix" due-to="Chris Allison, Phil Steitz">
+      Threading issue, NullPointerException and IllegalStateException in GenericKeyedObjectPool.
+    </action>
+    <action dev="ggregory" issue="POOL-352" type="fix" due-to="Volker Kleinschmidt, Gary Gregory">
+      CallStackUtils mishandles security manager check (partial fix.)
+    </action>
+  </release>  
+  <release version="2.6.0" date="2018-07-06" description="This is a maintenance release.">
+    <action dev="ggregory" issue="POOL-336" type="update" due-to="Wolfgang Glas">
+      GenericObjectPool's borrowObject lock if create() fails with Error.
+    </action>
+    <action dev="ggregory" issue="POOL-339" type="update">
+      Update optional library cglib from 3.2.5 to 3.2.6.
+    </action>
+    <action dev="markt" issue="POOL-337" type="fix" due-to="Reinald Verheij">
+      Ensure cancelled eviction tasks are removed from scheduler.
+    </action>
+    <action dev="ggregory" issue="POOL-341" type="update">
+      Update optional library asm-util from 6.0 to 6.1.1.
+    </action>
+    <action dev="ggregory" issue="POOL-342" type="update">
+      Update optional library asm-util from 6.1.1 to 6.2.
+    </action>
+    <action dev="ggregory" issue="POOL-338" type="fix" due-to="Michael C, Gary Gregory">
+      GenericObjectPool constructor may throw an exception under OSGi.
+    </action>
+    <action dev="ggregory" issue="POOL-324" type="fix" due-to="Jay Xu, Gary Gregory">
+      org.apache.commons.pool2.impl.GenericObjectPool.getFactoryType() throws java.lang.ClassCastException.
+    </action>
+    <action dev="ggregory" issue="POOL-344" type="fix" due-to="Yulin Wang">
+      Delete repeated call startEvictor.
+    </action>
+  </release>
+  <release version="2.5.0" date="2017-12-16" description="This is a minor release, updating to Java 7.">
+    <action dev="ggregory" issue="POOL-331" type="update">
+      Update from Java 6 to 7.
+    </action>
+    <action dev="ggregory" issue="POOL-330" type="delete">
+      Drop Ant build.
+    </action>
+    <action dev="ggregory" issue="POOL-332" type="add">
+      ObjectPool and KeyedObject pool should extend Closeable.
+    </action>
+    <action dev="ggregory" issue="POOL-333" type="update">
+      Update optional dependency asm-util from 5.2 to 6.0.
+    </action>
+    <action dev="ggregory" issue="POOL-334" type="update">
+      org.apache.commons.pool2.impl.ThrowableCallStack.Snapshot is missing serialVersionUID.
+    </action>
+    <action dev="mattsicker" issue="POOL-335" type="add">
+      Make abandoned logging stack trace requirements configurable. This also reverts
+      the default behavior introduced by POOL-320.
+    </action>
+    <action dev="mattsicker" issue="POOL-335" type="add">
+      Make abandoned logging stack trace requirements configurable. This also reverts
+      the default behavior introduced by POOL-320.
+    </action>
+  </release>
+  <release version="2.4.3" date="2017-10-24" description="This is a patch release, including bug fixes only.">
+    <action dev="ggregory" issue="POOL-328" type="fix" due-to="Lorenzo Solano Martinez">
+      Documentation with repeated words (sources, tests, and examples).
+    </action>
+    <action dev="ggregory" issue="POOL-317" type="fix" due-to="KeiichiFujino">
+      Correction of default value of softMinEvictableIdleTimeMillis in BaseObjectPoolConfig.
+    </action>
+    <action dev="ggregory" issue="POOL-309" type="fix" due-to="jolestar, Roopam Patekar">
+      Fix misspellings from "destory" to "destroy".
+    </action>
+    <action dev="markt" issue="POOL-306" type="fix" due-to="Adrian Crum">
+      Ensure BaseGenericObjectPool.IdentityWrapper#equals() follows the expected
+      contract for equals(). 
+    </action>
+    <action dev="markt" issue="POOL-303" type="fix">
+      Ensure that threads do not block indefinitely if more than maxTotal
+      threads try to borrow an object at the same time and the factory fails to
+      create any objects. 
+    </action>
+    <action dev="markt" issue="POOL-280" type="update" due-to="Jacopo Cappellato">
+      Small refactoring of borrowObject() to reduce code duplication.
+    </action>
+    <action dev="markt" issue="POOL-307" type="update" due-to="Anthony Whitford">
+      Replace inefficient use of keySet with entrySet in GKOP.
+    </action>
+    <action dev="markt" issue="POOL-310" type="fix" due-to="Ivan Iliev">
+      Ensure that threads using GKOP do not block indefinitely if more than
+      maxTotal threads try to borrow objects with different keys at the same
+      time and the factory destroys objects on return. 
+    </action>
+    <action dev="markt" type="fix">
+      Ensure that any class name used for evictionPolicyClassName represents a
+      class that implements EvictionPolicy.
+    </action>
+    <action dev="markt" issue="POOL-315" type="fix" due-to="KeiichiFujino">
+      Add a configurable delay (default 10 seconds) to wait when shutting down
+      an Evictor to allow the associated thread time to complete any current
+      evictions and to terminate.
+    </action>
+    <action dev="markt" type="fix">
+      Ensure that a call to GKOP preparePool() takes account of other threads
+      that might create objects concurrently, particularly the Evictor.
+    </action>
+    <action dev="mattsicker" issue="POOL-320" type="add">
+      Use more efficient stack walking mechanisms for usage tracking when possible.
+    </action>
+    <action dev="ggregory" issue="POOL-322" type="update">
+      Update optional cglib library from 3.1 to 3.2.5.
+    </action>
+    <action dev="ggregory" issue="POOL-323" type="update">
+      Update optional OW2 ASM from 5.0.4 to 5.2.
+    </action>
+  </release>
+  <release version="2.4.2" date="2015-08-01" description=
+ "This is a patch release, including bug fixes only.">
+    <action dev="psteitz" issue="POOL-298" type="fix">
+      Changed default jmxNameBase in BaseObjectPoolConfig to the correct (null)
+      default.
+    </action>
+    <action dev="psteitz" issue="POOL-300" type="fix">
+      Added PrintWriter flush to DefaultPooledObject's printStackTrace method.
+    </action>
+  </release>
+  <release version="2.4.1" date="2015-05-30" description=
+ "This is a patch release, replacing a defective binary jar in version 2.4. Other
+than the build configuration, the source distribution for version 2.4.1 is identical
+to version 2.4.">
+    <action dev="psteitz" issue="POOL-297" type="fix">
+      Reverted cobertura plugin update that caused binary jar corruption.
+    </action>
+  </release>
+  <release version="2.4" date="2015-05-27" description=
+ "This is a maintenance release that includes bug fixes and minor enhancements.">
+    <action dev="psteitz" type="fix" issue="POOL-287" due-to="Caleb Spare and Thomas Neidhart">
+      Fixed capacity leak when an object is offered from a GenericKeyedObjectPool while it is
+      being validated by the evictor. 
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-283">
+      Eliminated the requirement that objects managed by GenericObjectPool or
+      GenericKeyedObjectPool be discernible by equals.  Prior to this fix,
+      equal but distinct object instances could not be stored in the same pool.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-284">
+      Eliminated the requirement that object equality and hashcodes do not change
+      while objects are under management by GenericObjectPool or GenericKeyedObjectPool.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-289" due-to="Luke Winkenbach">
+      Fixed class loading for custom EvictionPolicy implementations that may not
+      be present in the class loader hierarchy of the Pool classes by falling
+      back to the class loader of the current class.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-285">
+      Ensured that when an instance that has already been returned to a pool is
+      returned again, the expected IllegalStateException is generated before the
+      returning object is re-validated or re-passivated.
+    </action>
+    <action dev="psteitz" type="add" issue="POOL-286">
+      Added preparePool method to GenericObjectPool.
+    </action>
+    <action dev="ggregory" type="update" issue="POOL-296">
+      Update asm-util from 5.0.3 to 5.0.4.
+    </action>
+    <action dev="psteitz" type="update" issue="POOL-293">
+      Exposed getEvictionPolicy as protected in BaseGenericObjectPool.
+    </action>
+  </release>
+  <release version="2.3" date="2014-12-30" description=
+"This is a maintenance release that includes bug fixes and minor enhancements.">  
+    <action dev="psteitz" type="fix" issue="POOL-279" due-to="Jacopo Cappellato">
+      Eliminated possibility that DefaultPoolObject#getIdleTimeMillis() could
+      return a negative value. Use by pool implementations would not hit this
+      bug. 
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-275">
+      Made wrapped BaseProxyHandler.pooledObject volatile.
+    </action>
+    <action dev="ecki" type="fix" issue="POOL-277" due-to="Lucas Pouzac">
+      Replace synchronisation with lock-free maxBorrowWaitTimeMillis to
+      increase scalability.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-276">
+      Ensure that objects are not validated on borrow when testOnBorrow is set
+      to false, testOnCreate is set to true and the pool is exhausted at the
+      point borrowObject() is called.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-270" due-to="Michael Berman">
+      Fixed error in GenericKeyedObjectPool constructor causing minEvictableIdleTimeMillis
+      to be used in place of timeBetweenEvictionRunsMillis in eviction timer setup
+      when a GenericKeyedObjectPoolConfig instance is supplied to the constructor.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-263">
+      Fix a threading issue that meant that concurrent calls to close() and
+      returnObject() could result in some returned objects not being destroyed.
+    </action>
+    <action dev="psteitz" type="add" issue="POOL-262">
+      Made fairness configurable for GenericObjectPool, GenericKeyedObjectPool.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-261">
+      Correctly mark cglib as an optional dependency and ensure that the OSGi
+      manifest information reflects that.
+    </action>
+    <action dev="markt" type="fix">
+      Improve performance of statistics collection for pools that extend
+      BaseGenericObjectPool.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-259">
+      Made client wait time statistics accurate when pools are configured to
+      block indefinitely.  Also modified computation to include latency clients
+      experience due to waiting on factory methods.
+    </action>
+    <action dev="ggregory" type="update" issue="POOL-273">
+      Update cglib to 3.1 from 3.0.
+    </action>
+    <action dev="ggregory" type="update" issue="POOL-274">
+      Update asm-util to 5.0.3 from 4.0.
+    </action>
+    <action dev="markt" type="fix">
+      Prevent potential memory leaks when the Pool is dereferenced without being
+      closed.
+    </action>
+    <action dev="markt" type="fix">
+      Prevent potential memory leaks with using an Evictor in a container
+      environment.
+    </action>
+    <action dev="markt" type="fix">
+      Protect against a user provided eviction policy throwing an exception and
+      stopping the Evictor thread.
+    </action>
+    <action dev="markt" type="fix">
+      Use the thread context class loader to load custom eviction policies. This
+      allows application provided eviction policies to be used in a container
+      environment when the pooling implementation is provided by the container.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-281">
+      Fix a potential infinite loop in the underlying Deque implementation.
+    </action>
+  </release>
+  <release version="2.2" date="2014-02-24" description=
+"This is a maintenance release that adds a new testOnCreate configuration option
+and fixes a small number of bugs.">
+    <action issue="POOL-248" dev="markt" type="fix" due-to="Warren Chen">
+      Ensure that if an attempt is made to return an object multiple times that
+      the current active and idle object counts are not corrupted.
+    </action>
+    <action issue="POOL-249" dev="markt" type="fix" due-to="Ville Skyttä">
+      Fix Javadoc issues when building docs with Java 8.
+    </action>
+    <action dev="markt" type="fix">
+      Fix the remaining Javadoc warnings.
+    </action>
+    <action dev="markt" type="add">
+      Add a new validation configuration option testOnCreate that tests an
+      object immediately after it is created.
+    </action>
+  </release>
+   <release version="2.1" date="2013-12-30" description=
+"This is a maintenance release that includes a small number of new features as well as 
+including bugfixes and test case improvements.">
+    <action issue="POOL-243" dev="psteitz" type="fix" due-to="Michal Sabo">
+      Added missing create counter decrement in GenericKeyedObjectPool create method on factory
+      exception path. Prior to this fix, exceptions thrown by factory makeObject calls could leak
+      per key capacity.
+    </action>
+    <action issue="POOL-240" dev="psteitz" type="fix" due-to="Dan McNulty">
+      Ensured that blocked threads waiting on a depleted pool get served when
+      objects are destroyed due to validation or passivation failures in
+      returnObject or when a checked out instance is invalidated.
+    </action>
+    <action issue="POOL-241" dev="markt" type="add" due-to="Bruno P. Kinoshita">
+      Expand the coverage of the unit tests.
+    </action>
+    <action dev="markt" type="add">
+      Provide more control over the names under which Pools are registered in
+      JMX so components using the pools can register the pools they use under a
+      related name.
+    </action>
+    <action dev="markt" type="add">
+      Include the number of times an object has been borrowed from the Pool when
+      the DefaultPooledObject wrapper is used and expose this property via JMX.
+    </action>
+    <action issue="POOL-245" dev="markt" type="fix" due-to="Bruno P. Kinoshita">
+      Remove a duplicate null check and fix some typos in PoolUtils.
+    </action>
+    <action issue="POOL-246" dev="markt" type="fix" due-to="Bruno P. Kinoshita">
+      Make the toString() method of ErodingKeyedObjectPool consistent with the
+      other pools.
+    </action>
+    <action issue="POOL-245" dev="markt" type="add" due-to="Bruno P. Kinoshita">
+      Further expansion of the coverage of the unit tests.
+    </action>
+  </release>
+  <release version="2.0" date="2013-11-11" description=
+"This is a major new release that provides significant performance improvements
+in high concurrency environments. Pools now provide a mechanism for tracking
+objects that have been borrowed from the pool but not returned. There have been
+numerous API changes to support these and other new features as well as to
+clarify behaviour and improve consistency across the API. This release requires
+JDK level 1.6 or above.">
+    <action issue="POOL-211" dev="markt" type="add" due-to="Brad Koehn">
+      Add support for proxy wrappers to ObjectPool and KeyedObjectPool. The
+      primary advantage of these wrappers is that use of pooled objects is
+      prevented after they have been returned to the pool.
+    </action>
+    <action issue="POOL-229" dev="psteitz" type="update">
+      Added abandoned object removal (moved from DBCP) to GenericObjectPool.
+    </action>
+    <action issue="POOL-221" dev="markt" type="fix" >
+      PooledObject.state does not need to be volatile
+    </action>
+    <action issue="POOL-220" dev="markt" type="fix">
+      Suppress a FindBugs warning
+    </action>
+    <action issue="POOL-217" dev="markt" type="update"  due-to="sebb">
+      Use an IODH for PoolUtils.MIN_IDLE_TIMER
+    </action>
+    <action issue="POOL-216" dev="markt" type="update" >
+      GenericKeyedObjectPool.ensureMinIdle(K) does not need to check getMinIdlePerKey().
+    </action>
+    <action issue="POOL-215" dev="markt" type="fix" >
+      GenericKeyedObjectPool - multiple mutable fields not published safely.
+    </action>
+    <action issue="POOL-214" dev="markt" type="fix" >
+      GenericObjectPool.evictionPolicy not thread-safe
+    </action>
+    <action issue="POOL-212" dev="markt" type="fix" >
+      GenericObjectPool allows maxIdle &lt; minIdle
+    </action>
+    <action issue="POOL-207" dev="markt" type="fix" >
+      GenericKeyedObjectPool.clear() has unnecessary null check of objectDequeue
+    </action>
+    <action issue="POOL-201" dev="markt" type="fix" >
+      Classes Generic[Keyed]ObjectPoolConfig are generic - but why? 
+    </action>
+    <action issue="POOL-200" dev="markt" type="fix" >
+      GOP/GKOP don't consistently use getters to access fields
+    </action>
+    <action issue="POOL-199" dev="markt" type="fix" >
+      GOP/GKOP evict() method is not synchronised and is not thread-safe
+    </action>
+    <action issue="POOL-197" dev="markt" type="fix" >
+      PooledObject: risky init of lastBorrowTime &amp; lastReturnTime
+    </action>
+    <action issue="POOL-196" dev="markt" type="fix" >
+      PooledObject.getActiveTimeMillis() does not synch. access to lastReturnTime and lastBorrowTime
+    </action>
+    <action issue="POOL-194" dev="simonetripodi" type="update" date="2011-12-12">
+      Replace synchronized blocks in PoolUtils with Read/Write locks.
+    </action>
+    <action issue="POOL-83" dev="simonetripodi" type="update" date="2011-04-28">
+      Support Java 1.5 Generics.
+    </action>
+    <action issue="POOL-186" dev="simonetripodi" type="update" date="2011-04-28">
+      Developer documentation and examples have to be updated once the 2.0 repackaging has been done
+    </action>
+    <action dev="markt" type="update">
+      Switch GOP to use a pooling mechanism based on java.util.concurrent and a
+      LinkedBlockingQueue implementation from Apache Harmony (originally by Doug
+      Lea and the JSR-166 expert group).
+    </action>
+    <action dev="markt" type="update">
+      Make deprecated protected attributes private, requiring that access is via
+      the appropriate getters. 
+    </action>
+    <action dev="markt" type="update">
+      Code clean-up. Add missing @Override annotations, remove unused code,
+      remove deprecated code and unnecessary code.
+    </action>
+    <action dev="markt" type="update">
+      Introduce an Enum (WhenExhaustedAction) to control pool behaviour when no
+      more objects are available to allocate.
+    </action>
+    <action dev="markt" type="update">
+      Remove WhenExhuastedAction.GROW since it is equivalent to
+      WhenExhuastedAction.FAIL with a maxActive value of Integer.MAX_VALUE. 
+    </action>
+    <action issue="POOL-188" dev="markt" type="fix" due-to="sebb">
+      Remove confusing method PoolUtils.ErodingKeyedObjectPool.numIdle(K key).
+    </action>
+    <action issue="POOL-155" dev="markt" type="update">
+      Guard against multiple returns of the same object to the pool and ensure
+      that only objects borrowed from the pool are returned to it.
+    </action>
+    <action issue="POOL-150" dev="markt" type="fix">
+      Ensure GKOP.preparePool() throws an exception if no factory has been
+      defined.
+    </action>
+    <action issue="POOL-134" dev="markt" type="fix">
+      Add the ability to specify a per call wait time when borrowing an object.
+    </action>
+    <action issue="POOL-121" dev="markt" type="fix">
+      Provide a name for the eviction timer thread.
+    </action>
+    <action dev="markt" type="update">
+      Remove setFactory() method from GOP.
+    </action>
+    <action issue="POOL-173" dev="markt" type="fix">
+      Reduce duplication in configuration code.
+    </action>
+    <action issue="POOL-178" dev="markt" type="fix">
+      Re-factor common code into common base classes.
+    </action>
+    <action issue="POOL-172" dev="markt" type="update">
+      Expose GOP and GKOP attributes via JMX.
+    </action>
+    <action issue="POOL-98" dev="markt" type="update">
+      Add additional attributes (also accessible via JMX) for monitoring.
+    </action>
+    <action dev="markt" type="update">
+      Change meaning of zero for maxWait to a maximum wait of zero milliseconds
+      rather than the unexpected infinite wait.
+    </action>
+    <action issue="POOL-100" dev="markt" type="fix">
+      Allow custom eviction policies to be defined.
+    </action>
+    <action issue="POOL-211" dev="markt" type="add" due-to="Brad Koehn">
+      Add support for proxy wrappers for ObjectPool and KeyedObjectPool. The
+      primary advantage of using these wrappers is that use of pooled objects
+      is prevented after they have been returned to the pool.  
+    </action>
+  </release>
+  <release version="1.6" date="2012-01-07" description="Adds generics and requires Java 5.">
+    <action dev="ggregory" type="add" issue="POOL-208">
+      Support Java 1.5 Generics in version 1.x.
+    </action>
+  </release>
+  <release version="1.5.7" date="2011-12-20" description="This is a patch release, including bugfixes only.">
+    <action dev="psteitz" type="fix" issue="POOL-189" due-to="Bill Speirs">
+      Awaken threads waiting on borrowObject when a pool has been closed and have them throw
+      IllegalStateException.  Prior to the fix for this issue, threads waiting in borrowObject when
+      close was invoked on GOP or GKOP would block indefinitely.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-192" due-to="Helge Dannenberg">
+      Corrected total internal processing counter update in destroy.  Prior to the fix
+      for this issue, clear(key) was leaking capacity associated with elements in the
+      pool being cleared.
+    </action>
+  </release>
+  <release version="1.5.6" date="2011-04-03" description="This is a patch release, including bugfixes only.">
+    <action dev="markt" type="fix" issue="POOL-179" due-to="Axel Grossmann">
+      Correctly handle an InterruptedException when waiting for an object from
+      the pool.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-180">
+      Only stop tracking objects for a key when there are no idle objects, no
+      active objects and no objects being processed.
+    </action>
+    <action dev="markt" type="update" issue="POOL-181">
+      Make BaseObjectPool.isClosed() public.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-184" due-to="Adrian Nistor">
+      Correct bug that could lead to inappropriate pool starvation when evict()
+      and borrowObject() are called concurrently.
+    </action>
+    <action dev="markt" type="fix" due-to="psteitz">
+      Fix performance issues when object destruction has latency.
+    </action>
+  </release>
+  <release version="1.5.5" date="2010-09-10" description=
+     "This is a patch release, including bugfixes, documentation improvements and some deprecations
+      in preparation for pool 2.0.">
+    <action dev="psteitz" type="update" issue="POOL-169">
+      In preparation for pool 2.0, deprecated direct access to protected fields
+      and setFactory methods.  In pool 2.0, pool object factories will be immutable.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-158">
+      Made GenericKeyedObjectPool._minIdle volatile.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-161">
+      Made the default context class loader for the eviction thread the same loader that loads
+      the library to prevent memory leaks in multiple class loader environments.
+    </action>
+    <action dev="sebb" type="update" issue="POOL-166">
+      GenericKeyedObjectPool.destroy could use entrySet() rather than keySet() followed by get()
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-157" due-to="David Hu">
+      GenericObjectPool and GenericKeyedObjectPool setFactory methods destroy idle instances
+      in the pool by contract. Prior to the fix for this issue, newly set factories were being
+      used to destroy idle instances, rather than the factories used to create them.  The 
+      setFactory methods have also been deprecated, to be removed in version 2.0.
+    </action>
+    <action dev="sebb" type="update" issue="POOL-156">
+      ObjectPool classes can ignore Throwable. Added consistent handling for Throwables
+      that are normally swallowed including always re-throwing certain Throwables (e.g. ThreadDeath).
+    </action>
+    <action dev="markt" type="fix" issue="POOL-162">
+      When waiting threads are interrupted, GOP, GKOP may leak capacity.
+    </action>
+    <action dev="psteitz" type="fix" issue="POOL-154" due-to="Glen Mazza">
+      Documentation for the close method in GenericObjectPool and GenericKeyedObjectPool
+      incorrectly states that this method does not clear the pool.
+    </action>
+  </release>
+  <release version="1.5.4" date="2009-11-20" description=
+ "This is a patch release containing a fix for POOL-152, a regression
+introduced in version 1.5.">
+    <action dev="markt" type="fix" issue="POOL-152" due-to="Bushov Alexander">
+      GenericObjectPool can block forever in borrowObject when the pool is exhausted and a newly created
+      object fails validation. When borrowing an object if a new object is created but validate fails,
+      the latch should not be returned to the queue as an exception will be thrown.
+    </action>
+  </release>
+  <release version="1.5.3" date="2009-09-21" description=
+"This is a patch release containing a fix for POOL-149, a regression
+introduced in version 1.5.">
+    <action dev="markt" type="fix" issue="POOL-149" due-to="Shuyang Zhou">
+      Fix case where a thread could end up waiting indefinitely even if objects
+      were available. Also fixes a couple of leaks in the internal processing
+      object count that could lead to pool exhaustion.
+    </action>
+  </release>
+  <release version="1.5.2" date="2009-07-12" description=
+"This is a patch release containing fixes for POOL-146 and POOL-147, regressions
+introduced in version 1.5.">
+    <action dev="markt" type="fix" issue="POOL-146">
+      Handle the case where one key has reached maxActive but other keys have not.
+      Prior to the fix for this issue, threads waiting on objects from keyed pools
+      still having instances available could be blocked by a thread requesting an
+      instance from an exhausted pool.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-147" due-to="Giambattista Bloisi">
+      Fix case where a thread could end up waiting indefinitely even if objects
+      were available.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-145">
+      Ensure that the GenericKeyedObjectPool idle object evictor does not visit the
+      same instance more than once per eviction run.
+    </action>
+  </release>
+  <release version="1.5.1" date="2009-06-16" description=
+"This is a patch release containing a fix for POOL-144, a regression introduced
+in version 1.5.">
+    <action dev="markt" type="fix" issue="POOL-144">
+      When exhausted action is set to WHEN_EXHAUSTED_BLOCK, maxwait is positive and
+      client threads time out waiting for idle objects, capacity can be "leaked"
+      from GenericObjectPools and GeneritCkeyedObjectPools. 
+    </action>
+  </release>
+  <release version="1.5" date="2009-06-10" description=
+"This is a maintenance release including several important bug fixes. This release
+is source and binary compatible with versions 1.3 and 1.4 of commons pool. In addition
+to resolving some important concurrency-related bugs (POOL-135, POOL-125, POOL-29
+POOL-107) this release implements a fairness algorithm to ensure that threads waiting
+for available object instances from GenericObjectPools and GenericKeyedObjectPools are served
+in request arrival order.">
+    <action dev="markt" type="fix" issue="POOL-139" due-to="Sebastian Bazley">
+      StackKeyedObjectPool.getNumActive() needs to be synchronized.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-137" due-to="Sebastian Bazley">
+      Inconsistent synchronization in GenericObjectPool; constant fields should be final.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-75" due-to="Takayuki Kaneko and Gordon Mohr">
+       GenericObjectPool not FIFO with respect to borrowing threads.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-135">
+      _numActive > _maxActive under load
+    </action>
+    <action dev="markt" type="fix" issue="POOL-125">
+      Insufficient control over concurrent access to pooled objects by Evictor, client threads.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-107">
+      Number of connections created has crossed more than maxActive.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-122">
+      java.util.Timer in EvictionTimer does not recover from OutOfMemoryError in Evictor.
+    </action>
+    <action dev="markt" type="fix" issue="POOL-133">
+      Failed object creation may result in invalid active count in GKOP.
+    </action>
+  </release>
+  <release version="1.4" date="2008-01-15" description=
+"This is a maintenance release including numerous bug fixes. This release
+is source and binary compatible with version 1.3 of commons pool, but
+there are some behavior changes introduced to resolve bugs, remove ambiguity
+or improve robustness. Among these are the change in default behavior of
+GenericObjectPool and GenericKeyedObjectPool from FIFO back to LIFO queues
+(as in 1.2 and earlier). The LIFO/FIFO behavior is now configurable. Some of
+the extra synchronization included in version 1.3 was removed / refactored to
+improve performance. The javadoc has also been made more complete and explicit.
+See the detailed list of changes below for specifics on fixed bugs and behavior
+changes in Commons Pool 1.4. This version of Commons Pool depends only on
+JDK version 1.3 or higher. Classes implementing pools are all intended to be
+threadsafe.">
+      <action dev="sandymac" type="fix">
+        Fixed constructor which was ignoring maxTotal parameter: 
+          GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction,
+          long maxWait, int maxIdle, int maxTotal, boolean testOnBorrow, boolean testOnReturn,
+          long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis,
+          boolean testWhileIdle)
+      </action>
+      <action dev="sandymac" type="fix">
+        Changed StackKeyedObjectPool to discard stalest, not freshest, idle object when maxSleeping is reached.
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-102" due-to="John Sumsion">
+        Allowed blocked threads in GenericObjectPool borrowObject to be interrupted.
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-86">
+        Fixes to address idle object eviction and LIFO/FIFO behavior reported
+        in POOL-86. Made LIFO/FIFO behavior configurable for GenericObjectPool and
+        GenericKeyedObjectPool, with default set back to LIFO (reverting to 1.2 behavior).
+        Fixed GOP, GKOP evict method and added tests to ensure objects are visited in
+        oldest-to-youngest order. Changed backing store for GOP, GKOP pools back to Commons
+        Collections CursorableLinkedList (brought this class in, repackaged with package scope).
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-110" due-to="Alexander Pogrebnyak">
+        Changed the default setting for Config.softMinEvictableIdleTimeMillis to
+        GenericObjectPool.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS (was
+        being incorrectly defaulted to DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS).
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-97" due-to="Mark Thomas">
+         Added a wrapper for the shared idle object eviction timer for all
+         pools. The wrapper class wraps the Timer and keeps track of how many
+         pools are using it. If no pools are using the timer, it is canceled.
+         This prevents a thread being left running which, in application server
+         environments, can lead to memory leaks and/or prevent applications
+         from shutting down or reloading cleanly.
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-93"  
+      due-to="Mark Thomas">
+        Reduced synchronization in GenericObjectPool, GenericKeyedObjectPool.
+        Factory method activations within synchronized blocks were causing
+        performance problems in DBCP and other applications where factory
+        methods could block. Fixes both POOL-93 and POOL-108.
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-113">
+        Made _testOnBorrow, _testOnReturn volatile and removed synchronization
+        in associated getters and setters in GenericObjectPool,
+        GenericKeyedObjectPool. Made getNumIdle synchronized in
+        StackKeyedObjectPool. 
+      </action>
+      <action dev="psteitz" type="fix" issue="POOL-116">
+        Fixed an error in the GenericKeyedObjectPool constructor that takes
+        a Config instance as a parameter. The minIdle setting in the Config
+        was being ignored by the constructor.
+      </action>
+      <action def="psteitz" type="fix" issue="POOL-117">
+        Made behavior on instance validation failure consistent across pools,
+        eliminating possible infinite loops in StackObjectPool,
+        StackKeyedObjectPool, SoftReferenceObjectPool when factory fails to
+        create valid objects. 
+      </action>
+      <action dev="sandymac" type="update">
+        When no factory has been defined, addObject now throws 
+        IllegalStateExecption instead of NullPointerException for all pools.
+      </action>
+      <action dev="sandymac" type="update">
+        SoftReferenceObjectPool. Improved the accuracy of getNumIdle by
+        "pruning" references to objects that have been garbage collected.
+      </action>
+      <action dev="sandymac" type="update">
+        GenericObjectPool, GenericKeyedObjectPool, SoftReferenceObjectPool,
+        StackObjectPool. Eliminated IllegalStateExceptions when the following
+        operations are attempted on a closed pool: getNumActive, getNumIdle, 
+        returnObject, invalidateObject.  In each case, the operation is allowed
+        to proceed, reporting the state of the pool that is being shut down, or
+        destroying objects returning to the closed pool.
+      </action>
+      <action dev="sandymac" type="update">
+        StackObjectPool, SoftReferenceObjectPool, GenericKeyedObjectPool. Allowed
+        borrowObject to continue (either examining additional idle instances or
+        with makeObject) when an exception is encountered activating an idle
+        object instead of propagating the exception to the client.  Also made
+        addObject propagate (not swallow) exceptions when passivating newly
+        created instances. 
+      </action>
+      <action dev="psteitz" type="update">
+        StackKeyedObjectPool. Added validation check for objects returned
+        from borrowObject. 
+      </action>
+      <action dev="sandymac" type="update">
+        BaseObjectPool, BaseKeyedObjectPool. Instead of throwing 
+        UnsupportedOperationException, the base class implementations
+        of getNumIdle and getNumActive return negative values. The
+        base implementation of close in BaseObjectPool no longer throws
+        IllegalStateException when invoked on an already closed pool.
+      </action>
+      
+    </release>
+
+    <release version="1.3" date="2006-04-06" description="1.x bugfix release">
+      <action type="fix">A large number of bug fixes. See release notes for changes.</action>
+    </release>
+
+    <release version="1.2" date="2004-06-07" description="bugfixes">
+      <action dev="dirkv" type="fix">
+           GenericKeyedObjectPoolFactory Config Constructor is incorrect
+      </action>
+      <action dev="dirkv" type="fix">
+        Not possible to extend GenericObjectPool.returnObject() without affecting addObject()
+      </action>
+    </release>
+
+    <release version="1.1" date="2003-10-20" description="bugfixes">
+      <action type="fix">A lot of corner cases were fixed</action>
+      <action type="fix">Performance improvement by optimizing pool synchronization, the critical code paths were optimized by reducing pool synchronization but we also added more synchronization where needed</action>
+      <action type="fix">New minIdle feature: the minimum number of objects allowed in the pool before the evictor thread (if active) spawns new objects. (Note no objects are created when: numActive + numIdle >= maxActive)</action>
+      <action type="fix">New maxTotal feature: a cap on the total number of instances controlled by a pool. Only for GenericKeyedObjectPool where maxActive is a cap on the number of active instances from the pool (per key).</action>
+      <action type="fix">UML Class and sequence diagrams</action>
+      <action type="fix">See bugzilla for more changes</action>
+    </release>
+
+    <release version="1.0.1" date="2002-08-12">
+      <action type="fix">No change log available.</action>
+    </release>
+
+    <release version="1.0" date="2002-05-04">
+      <action type="add">No change log available.</action>
+    </release>
+  </body>
+</document>
diff --git a/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java b/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
index 8efb01f..970a3db 100644
--- a/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
@@ -1,1413 +1,1411 @@
-/*
- * 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 java.io.PrintWriter;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.lang.management.ManagementFactory;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.TimerTask;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanRegistrationException;
-import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
-import javax.management.NotCompliantMBeanException;
-import javax.management.ObjectName;
-
-import org.apache.commons.pool2.BaseObject;
-import org.apache.commons.pool2.PooledObject;
-import org.apache.commons.pool2.PooledObjectState;
-import org.apache.commons.pool2.SwallowedExceptionListener;
-
-/**
- * Base class that provides common functionality for {@link GenericObjectPool}
- * and {@link GenericKeyedObjectPool}. The primary reason this class exists is
- * reduce code duplication between the two pool implementations.
- *
- * @param <T> Type of element pooled in this pool.
- *
- * This class is intended to be thread-safe.
- *
- * @since 2.0
- */
-public abstract class BaseGenericObjectPool<T> extends BaseObject {
-
-    // Constants
-    /**
-     * The size of the caches used to store historical data for some attributes
-     * so that rolling means may be calculated.
-     */
-    public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100;
-
-    private static final String EVICTION_POLICY_TYPE_NAME = EvictionPolicy.class.getName();
-
-    // Configuration attributes
-    private volatile int maxTotal =
-            GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
-    private volatile boolean blockWhenExhausted =
-            BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
-    private volatile long maxWaitMillis =
-            BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
-    private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
-    private final boolean fairness;
-    private volatile boolean testOnCreate =
-            BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
-    private volatile boolean testOnBorrow =
-            BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
-    private volatile boolean testOnReturn =
-            BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
-    private volatile boolean testWhileIdle =
-            BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
-    private volatile long timeBetweenEvictionRunsMillis =
-            BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
-    private volatile int numTestsPerEvictionRun =
-            BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
-    private volatile long minEvictableIdleTimeMillis =
-            BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
-    private volatile long softMinEvictableIdleTimeMillis =
-            BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
-    private volatile EvictionPolicy<T> evictionPolicy;
-    private volatile long evictorShutdownTimeoutMillis =
-            BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
-
-
-    // Internal (primarily state) attributes
-    final Object closeLock = new Object();
-    volatile boolean closed = false;
-    final Object evictionLock = new Object();
-    private Evictor evictor = null; // @GuardedBy("evictionLock")
-    EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
-    /*
-     * Class loader for evictor thread to use since, in a JavaEE or similar
-     * environment, the context class loader for the evictor thread may not have
-     * visibility of the correct factory. See POOL-161. Uses a weak reference to
-     * avoid potential memory leaks if the Pool is discarded rather than closed.
-     */
-    private final WeakReference<ClassLoader> factoryClassLoader;
-
-
-    // Monitoring (primarily JMX) attributes
-    private final ObjectName objectName;
-    private final String creationStackTrace;
-    private final AtomicLong borrowedCount = new AtomicLong(0);
-    private final AtomicLong returnedCount = new AtomicLong(0);
-    final AtomicLong createdCount = new AtomicLong(0);
-    final AtomicLong destroyedCount = new AtomicLong(0);
-    final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
-    final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
-    private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
-    private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
-    private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
-    private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L);
-    private volatile SwallowedExceptionListener swallowedExceptionListener = null;
-
-
-    /**
-     * Handles JMX registration (if required) and the initialization required for
-     * monitoring.
-     *
-     * @param config        Pool configuration
-     * @param jmxNameBase   The default base JMX name for the new pool unless
-     *                      overridden by the config
-     * @param jmxNamePrefix Prefix to be used for JMX name for the new pool
-     */
-    public BaseGenericObjectPool(final BaseObjectPoolConfig<T> config,
-            final String jmxNameBase, final String jmxNamePrefix) {
-        if (config.getJmxEnabled()) {
-            this.objectName = jmxRegister(config, jmxNameBase, jmxNamePrefix);
-        } else {
-            this.objectName = null;
-        }
-
-        // Populate the creation stack trace
-        this.creationStackTrace = getStackTrace(new Exception());
-
-        // save the current TCCL (if any) to be used later by the evictor Thread
-        final ClassLoader cl = Thread.currentThread().getContextClassLoader();
-        if (cl == null) {
-            factoryClassLoader = null;
-        } else {
-            factoryClassLoader = new WeakReference<>(cl);
-        }
-
-        fairness = config.getFairness();
-    }
-
-
-    /**
-     * Returns the maximum number of objects that can be allocated by the pool
-     * (checked out to clients, or idle awaiting checkout) at a given time. When
-     * negative, there is no limit to the number of objects that can be
-     * managed by the pool at one time.
-     *
-     * @return the cap on the total number of object instances managed by the
-     *         pool.
-     *
-     * @see #setMaxTotal
-     */
-    public final int getMaxTotal() {
-        return maxTotal;
-    }
-
-    /**
-     * Sets the cap on the number of objects that can be allocated by the pool
-     * (checked out to clients, or idle awaiting checkout) at a given time. Use
-     * a negative value for no limit.
-     *
-     * @param maxTotal  The cap on the total number of object instances managed
-     *                  by the pool. Negative values mean that there is no limit
-     *                  to the number of objects allocated by the pool.
-     *
-     * @see #getMaxTotal
-     */
-    public final void setMaxTotal(final int maxTotal) {
-        this.maxTotal = maxTotal;
-    }
-
-    /**
-     * Returns whether to block when the <code>borrowObject()</code> method is
-     * invoked when the pool is exhausted (the maximum number of "active"
-     * objects has been reached).
-     *
-     * @return <code>true</code> if <code>borrowObject()</code> should block
-     *         when the pool is exhausted
-     *
-     * @see #setBlockWhenExhausted
-     */
-    public final boolean getBlockWhenExhausted() {
-        return blockWhenExhausted;
-    }
-
-    /**
-     * Sets whether to block when the <code>borrowObject()</code> method is
-     * invoked when the pool is exhausted (the maximum number of "active"
-     * objects has been reached).
-     *
-     * @param blockWhenExhausted    <code>true</code> if
-     *                              <code>borrowObject()</code> should block
-     *                              when the pool is exhausted
-     *
-     * @see #getBlockWhenExhausted
-     */
-    public final void setBlockWhenExhausted(final boolean blockWhenExhausted) {
-        this.blockWhenExhausted = blockWhenExhausted;
-    }
-
-    protected void setConfig(final BaseObjectPoolConfig<T> conf) {
-        setLifo(conf.getLifo());
-        setMaxWaitMillis(conf.getMaxWaitMillis());
-        setBlockWhenExhausted(conf.getBlockWhenExhausted());
-        setTestOnCreate(conf.getTestOnCreate());
-        setTestOnBorrow(conf.getTestOnBorrow());
-        setTestOnReturn(conf.getTestOnReturn());
-        setTestWhileIdle(conf.getTestWhileIdle());
-        setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun());
-        setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis());
-        setTimeBetweenEvictionRunsMillis(conf.getTimeBetweenEvictionRunsMillis());
-        setSoftMinEvictableIdleTimeMillis(conf.getSoftMinEvictableIdleTimeMillis());
-        final EvictionPolicy<T> policy = conf.getEvictionPolicy();
-        if (policy == null) {
-            // Use the class name (pre-2.6.0 compatible)
-            setEvictionPolicyClassName(conf.getEvictionPolicyClassName());
-        } else {
-            // Otherwise, use the class (2.6.0 feature)
-            setEvictionPolicy(policy);
-        }
-        setEvictorShutdownTimeoutMillis(conf.getEvictorShutdownTimeoutMillis());
-    }
-
-    /**
-     * Returns the maximum amount of time (in milliseconds) the
-     * <code>borrowObject()</code> method should block before throwing an
-     * exception when the pool is exhausted and
-     * {@link #getBlockWhenExhausted} is true. When less than 0, the
-     * <code>borrowObject()</code> method may block indefinitely.
-     *
-     * @return the maximum number of milliseconds <code>borrowObject()</code>
-     *         will block.
-     *
-     * @see #setMaxWaitMillis
-     * @see #setBlockWhenExhausted
-     */
-    public final long getMaxWaitMillis() {
-        return maxWaitMillis;
-    }
-
-    /**
-     * Sets the maximum amount of time (in milliseconds) the
-     * <code>borrowObject()</code> method should block before throwing an
-     * exception when the pool is exhausted and
-     * {@link #getBlockWhenExhausted} is true. When less than 0, the
-     * <code>borrowObject()</code> method may block indefinitely.
-     *
-     * @param maxWaitMillis the maximum number of milliseconds
-     *                      <code>borrowObject()</code> will block or negative
-     *                      for indefinitely.
-     *
-     * @see #getMaxWaitMillis
-     * @see #setBlockWhenExhausted
-     */
-    public final void setMaxWaitMillis(final long maxWaitMillis) {
-        this.maxWaitMillis = maxWaitMillis;
-    }
-
-    /**
-     * Returns whether the pool has LIFO (last in, first out) behaviour with
-     * respect to idle objects - always returning the most recently used object
-     * from the pool, or as a FIFO (first in, first out) queue, where the pool
-     * always returns the oldest object in the idle object pool.
-     *
-     * @return <code>true</code> if the pool is configured with LIFO behaviour
-     *         or <code>false</code> if the pool is configured with FIFO
-     *         behaviour
-     *
-     * @see #setLifo
-     */
-    public final boolean getLifo() {
-        return lifo;
-    }
-
-    /**
-     * Returns whether or not the pool serves threads waiting to borrow objects fairly.
-     * True means that waiting threads are served as if waiting in a FIFO queue.
-     *
-     * @return <code>true</code> if waiting threads are to be served
-     *             by the pool in arrival order
-     */
-    public final boolean getFairness() {
-        return fairness;
-    }
-
-    /**
-     * Sets whether the pool has LIFO (last in, first out) behaviour with
-     * respect to idle objects - always returning the most recently used object
-     * from the pool, or as a FIFO (first in, first out) queue, where the pool
-     * always returns the oldest object in the idle object pool.
-     *
-     * @param lifo  <code>true</code> if the pool is to be configured with LIFO
-     *              behaviour or <code>false</code> if the pool is to be
-     *              configured with FIFO behaviour
-     *
-     * @see #getLifo()
-     */
-    public final void setLifo(final boolean lifo) {
-        this.lifo = lifo;
-    }
-
-    /**
-     * Returns whether objects created for the pool will be validated before
-     * being returned from the <code>borrowObject()</code> method. Validation is
-     * performed by the <code>validateObject()</code> method of the factory
-     * associated with the pool. If the object fails to validate, then
-     * <code>borrowObject()</code> will fail.
-     *
-     * @return <code>true</code> if newly created objects are validated before
-     *         being returned from the <code>borrowObject()</code> method
-     *
-     * @see #setTestOnCreate
-     *
-     * @since 2.2
-     */
-    public final boolean getTestOnCreate() {
-        return testOnCreate;
-    }
-
-    /**
-     * Sets whether objects created for the pool will be validated before
-     * being returned from the <code>borrowObject()</code> method. Validation is
-     * performed by the <code>validateObject()</code> method of the factory
-     * associated with the pool. If the object fails to validate, then
-     * <code>borrowObject()</code> will fail.
-     *
-     * @param testOnCreate  <code>true</code> if newly created objects should be
-     *                      validated before being returned from the
-     *                      <code>borrowObject()</code> method
-     *
-     * @see #getTestOnCreate
-     *
-     * @since 2.2
-     */
-    public final void setTestOnCreate(final boolean testOnCreate) {
-        this.testOnCreate = testOnCreate;
-    }
-
-    /**
-     * Returns whether objects borrowed from the pool will be validated before
-     * being returned from the <code>borrowObject()</code> method. Validation is
-     * performed by the <code>validateObject()</code> method of the factory
-     * associated with the pool. If the object fails to validate, it will be
-     * removed from the pool and destroyed, and a new attempt will be made to
-     * borrow an object from the pool.
-     *
-     * @return <code>true</code> if objects are validated before being returned
-     *         from the <code>borrowObject()</code> method
-     *
-     * @see #setTestOnBorrow
-     */
-    public final boolean getTestOnBorrow() {
-        return testOnBorrow;
-    }
-
-    /**
-     * Sets whether objects borrowed from the pool will be validated before
-     * being returned from the <code>borrowObject()</code> method. Validation is
-     * performed by the <code>validateObject()</code> method of the factory
-     * associated with the pool. If the object fails to validate, it will be
-     * removed from the pool and destroyed, and a new attempt will be made to
-     * borrow an object from the pool.
-     *
-     * @param testOnBorrow  <code>true</code> if objects should be validated
-     *                      before being returned from the
-     *                      <code>borrowObject()</code> method
-     *
-     * @see #getTestOnBorrow
-     */
-    public final void setTestOnBorrow(final boolean testOnBorrow) {
-        this.testOnBorrow = testOnBorrow;
-    }
-
-    /**
-     * Returns whether objects borrowed from the pool will be validated when
-     * they are returned to the pool via the <code>returnObject()</code> method.
-     * Validation is performed by the <code>validateObject()</code> method of
-     * the factory associated with the pool. Returning objects that fail validation
-     * are destroyed rather then being returned the pool.
-     *
-     * @return <code>true</code> if objects are validated on return to
-     *         the pool via the <code>returnObject()</code> method
-     *
-     * @see #setTestOnReturn
-     */
-    public final boolean getTestOnReturn() {
-        return testOnReturn;
-    }
-
-    /**
-     * Sets whether objects borrowed from the pool will be validated when
-     * they are returned to the pool via the <code>returnObject()</code> method.
-     * Validation is performed by the <code>validateObject()</code> method of
-     * the factory associated with the pool. Returning objects that fail validation
-     * are destroyed rather then being returned the pool.
-     *
-     * @param testOnReturn <code>true</code> if objects are validated on
-     *                     return to the pool via the
-     *                     <code>returnObject()</code> method
-     *
-     * @see #getTestOnReturn
-     */
-    public final void setTestOnReturn(final boolean testOnReturn) {
-        this.testOnReturn = testOnReturn;
-    }
-
-    /**
-     * Returns whether objects sitting idle in the pool will be validated by the
-     * idle object evictor (if any - see
-     * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
-     * by the <code>validateObject()</code> method of the factory associated
-     * with the pool. If the object fails to validate, it will be removed from
-     * the pool and destroyed.
-     *
-     * @return <code>true</code> if objects will be validated by the evictor
-     *
-     * @see #setTestWhileIdle
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final boolean getTestWhileIdle() {
-        return testWhileIdle;
-    }
-
-    /**
-     * Returns whether objects sitting idle in the pool will be validated by the
-     * idle object evictor (if any - see
-     * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
-     * by the <code>validateObject()</code> method of the factory associated
-     * with the pool. If the object fails to validate, it will be removed from
-     * the pool and destroyed.  Note that setting this property has no effect
-     * unless the idle object evictor is enabled by setting
-     * <code>timeBetweenEvictionRunsMillis</code> to a positive value.
-     *
-     * @param testWhileIdle
-     *            <code>true</code> so objects will be validated by the evictor
-     *
-     * @see #getTestWhileIdle
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final void setTestWhileIdle(final boolean testWhileIdle) {
-        this.testWhileIdle = testWhileIdle;
-    }
-
-    /**
-     * Returns the number of milliseconds to sleep between runs of the idle
-     * object evictor thread. When non-positive, no idle object evictor thread
-     * will be run.
-     *
-     * @return number of milliseconds to sleep between evictor runs
-     *
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final long getTimeBetweenEvictionRunsMillis() {
-        return timeBetweenEvictionRunsMillis;
-    }
-
-    /**
-     * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
-     * <ul>
-     * <li>When positive, the idle object evictor thread starts.</li>
-     * <li>When non-positive, no idle object evictor thread runs.</li>
-     * </ul>
-     *
-     * @param timeBetweenEvictionRunsMillis
-     *            number of milliseconds to sleep between evictor runs
-     *
-     * @see #getTimeBetweenEvictionRunsMillis
-     */
-    public final void setTimeBetweenEvictionRunsMillis(
-            final long timeBetweenEvictionRunsMillis) {
-        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
-        startEvictor(timeBetweenEvictionRunsMillis);
-    }
-
-    /**
-     * Returns the maximum number of objects to examine during each run (if any)
-     * of the idle object evictor thread. When positive, the number of tests
-     * performed for a run will be the minimum of the configured value and the
-     * number of idle instances in the pool. When negative, the number of tests
-     * performed will be <code>ceil({@link #getNumIdle}/
-     * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
-     * value is <code>-n</code> roughly one nth of the idle objects will be
-     * tested per run.
-     *
-     * @return max number of objects to examine during each evictor run
-     *
-     * @see #setNumTestsPerEvictionRun
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final int getNumTestsPerEvictionRun() {
-        return numTestsPerEvictionRun;
-    }
-
-    /**
-     * Sets the maximum number of objects to examine during each run (if any)
-     * of the idle object evictor thread. When positive, the number of tests
-     * performed for a run will be the minimum of the configured value and the
-     * number of idle instances in the pool. When negative, the number of tests
-     * performed will be <code>ceil({@link #getNumIdle}/
-     * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
-     * value is <code>-n</code> roughly one nth of the idle objects will be
-     * tested per run.
-     *
-     * @param numTestsPerEvictionRun
-     *            max number of objects to examine during each evictor run
-     *
-     * @see #getNumTestsPerEvictionRun
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
-        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
-    }
-
-    /**
-     * Returns the minimum amount of time an object may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor (if any -
-     * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
-     * no objects will be evicted from the pool due to idle time alone.
-     *
-     * @return minimum amount of time an object may sit idle in the pool before
-     *         it is eligible for eviction
-     *
-     * @see #setMinEvictableIdleTimeMillis
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final long getMinEvictableIdleTimeMillis() {
-        return minEvictableIdleTimeMillis;
-    }
-
-    /**
-     * Sets the minimum amount of time an object may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor (if any -
-     * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
-     * no objects will be evicted from the pool due to idle time alone.
-     *
-     * @param minEvictableIdleTimeMillis
-     *            minimum amount of time an object may sit idle in the pool
-     *            before it is eligible for eviction
-     *
-     * @see #getMinEvictableIdleTimeMillis
-     * @see #setTimeBetweenEvictionRunsMillis
-     */
-    public final void setMinEvictableIdleTimeMillis(
-            final long minEvictableIdleTimeMillis) {
-        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
-    }
-
-    /**
-     * Returns the minimum amount of time an object may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor (if any -
-     * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
-     * with the extra condition that at least <code>minIdle</code> object
-     * instances remain in the pool. This setting is overridden by
-     * {@link #getMinEvictableIdleTimeMillis} (that is, if
-     * {@link #getMinEvictableIdleTimeMillis} is positive, then
-     * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
-     *
-     * @return minimum amount of time an object may sit idle in the pool before
-     *         it is eligible for eviction if minIdle instances are available
-     *
-     * @see #setSoftMinEvictableIdleTimeMillis
-     */
-    public final long getSoftMinEvictableIdleTimeMillis() {
-        return softMinEvictableIdleTimeMillis;
-    }
-
-    /**
-     * Sets the minimum amount of time an object may sit idle in the pool
-     * before it is eligible for eviction by the idle object evictor (if any -
-     * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
-     * with the extra condition that at least <code>minIdle</code> object
-     * instances remain in the pool. This setting is overridden by
-     * {@link #getMinEvictableIdleTimeMillis} (that is, if
-     * {@link #getMinEvictableIdleTimeMillis} is positive, then
-     * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
-     *
-     * @param softMinEvictableIdleTimeMillis
-     *            minimum amount of time an object may sit idle in the pool
-     *            before it is eligible for eviction if minIdle instances are
-     *            available
-     *
-     * @see #getSoftMinEvictableIdleTimeMillis
-     */
-    public final void setSoftMinEvictableIdleTimeMillis(
-            final long softMinEvictableIdleTimeMillis) {
-        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
-    }
-
-    /**
-     * Returns the name of the {@link EvictionPolicy} implementation that is
-     * used by this pool.
-     *
-     * @return  The fully qualified class name of the {@link EvictionPolicy}
-     *
-     * @see #setEvictionPolicyClassName(String)
-     */
-    public final String getEvictionPolicyClassName() {
-        return evictionPolicy.getClass().getName();
-    }
-
-    /**
-     * Sets the eviction policy for this pool.
-     *
-     * @param evictionPolicy
-     *            the eviction policy for this pool.
-     * @since 2.6.0
-     */
-    public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
-        this.evictionPolicy = evictionPolicy;
-    }
-
-    /**
-     * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
-     * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy}
-     * interface.
-     *
-     * @param evictionPolicyClassName
-     *            the fully qualified class name of the new eviction policy
-     * @param classLoader
-     *            the class loader to load the given {@code evictionPolicyClassName}.
-     *
-     * @see #getEvictionPolicyClassName()
-     * @since 2.6.0 If loading the class using the given class loader fails, use the class loader for the
-     *        {@link EvictionPolicy} interface.
-     */
-    public final void setEvictionPolicyClassName(final String evictionPolicyClassName, final ClassLoader classLoader) {
-        // Getting epClass here and now best matches the caller's environment
-        final Class<?> epClass = EvictionPolicy.class;
-        final ClassLoader epClassLoader = epClass.getClassLoader();
-        try {
-            try {
-                setEvictionPolicy(evictionPolicyClassName, classLoader);
-            } catch (final ClassCastException | ClassNotFoundException e) {
-                setEvictionPolicy(evictionPolicyClassName, epClassLoader);
-            }
-        } catch (final ClassCastException e) {
-            throw new IllegalArgumentException("Class " + evictionPolicyClassName + " from class loaders ["
-                    + classLoader + ", " + epClassLoader + "] do not implement " + EVICTION_POLICY_TYPE_NAME);
-        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
-                | InvocationTargetException | NoSuchMethodException e) {
-            final String exMessage = "Unable to create " + EVICTION_POLICY_TYPE_NAME + " instance of type "
-                    + evictionPolicyClassName;
-            throw new IllegalArgumentException(exMessage, e);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private void setEvictionPolicy(final String className, final ClassLoader classLoader)
-            throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
-        final Class<?> clazz = Class.forName(className, true, classLoader);
-        final Object policy = clazz.getConstructor().newInstance();
-        this.evictionPolicy = (EvictionPolicy<T>) policy;
-    }
-
-    /**
-     * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
-     * load the class using the thread context class loader. If that fails, the use the class loader for the
-     * {@link EvictionPolicy} interface.
-     *
-     * @param evictionPolicyClassName
-     *            the fully qualified class name of the new eviction policy
-     *
-     * @see #getEvictionPolicyClassName()
-     * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the
-     *        {@link EvictionPolicy} interface.
-     */
-    public final void setEvictionPolicyClassName(final String evictionPolicyClassName) {
-        setEvictionPolicyClassName(evictionPolicyClassName, Thread.currentThread().getContextClassLoader());
-    }
-
-    /**
-     * Gets the timeout that will be used when waiting for the Evictor to
-     * shutdown if this pool is closed and it is the only pool still using the
-     * the value for the Evictor.
-     *
-     * @return  The timeout in milliseconds that will be used while waiting for
-     *          the Evictor to shut down.
-     */
-    public final long getEvictorShutdownTimeoutMillis() {
-        return evictorShutdownTimeoutMillis;
-    }
-
-    /**
-     * Sets the timeout that will be used when waiting for the Evictor to
-     * shutdown if this pool is closed and it is the only pool still using the
-     * the value for the Evictor.
-     *
-     * @param evictorShutdownTimeoutMillis  the timeout in milliseconds that
-     *                                      will be used while waiting for the
-     *                                      Evictor to shut down.
-     */
-    public final void setEvictorShutdownTimeoutMillis(
-            final long evictorShutdownTimeoutMillis) {
-        this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
-    }
-
-    /**
-     * Closes the pool, destroys the remaining idle objects and, if registered
-     * in JMX, deregisters it.
-     */
-    public abstract void close();
-
-    /**
-     * Has this pool instance been closed.
-     * @return <code>true</code> when this pool has been closed.
-     */
-    public final boolean isClosed() {
-        return closed;
-    }
-
-    /**
-     * <p>Perform <code>numTests</code> idle object eviction tests, evicting
-     * examined objects that meet the criteria for eviction. If
-     * <code>testWhileIdle</code> is true, examined objects are validated
-     * when visited (and removed if invalid); otherwise only objects that
-     * have been idle for more than <code>minEvicableIdleTimeMillis</code>
-     * are removed.</p>
-     *
-     * @throws Exception when there is a problem evicting idle objects.
-     */
-    public abstract void evict() throws Exception;
-
-    /**
-     * Returns the {@link EvictionPolicy} defined for this pool.
-     *
-     * @return the eviction policy
-     * @since 2.4
-     * @since 2.6.0 Changed access from protected to public.
-     */
-    public EvictionPolicy<T> getEvictionPolicy() {
-        return evictionPolicy;
-    }
-
-    /**
-     * Verifies that the pool is open.
-     * @throws IllegalStateException if the pool is closed.
-     */
-    final void assertOpen() throws IllegalStateException {
-        if (isClosed()) {
-            throw new IllegalStateException("Pool not open");
-        }
-    }
-
-    /**
-     * <p>Starts the evictor with the given delay. If there is an evictor
-     * running when this method is called, it is stopped and replaced with a
-     * new evictor with the specified delay.</p>
-     *
-     * <p>This method needs to be final, since it is called from a constructor.
-     * See POOL-195.</p>
-     *
-     * @param delay time in milliseconds before start and between eviction runs
-     */
-    final void startEvictor(final long delay) {
-        synchronized (evictionLock) {
-            if (null != evictor) {
-                EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
-                evictor = null;
-                evictionIterator = null;
-            }
-            if (delay > 0) {
-                evictor = new Evictor();
-                EvictionTimer.schedule(evictor, delay, delay);
-            }
-        }
-    }
-
-    /**
-     * Stops the evictor.
-     */
-    void stopEvitor() {
-        startEvictor(-1L);
-    }
-    /**
-     * Tries to ensure that the configured minimum number of idle instances are
-     * available in the pool.
-     * @throws Exception if an error occurs creating idle instances
-     */
-    abstract void ensureMinIdle() throws Exception;
-
-
-    // Monitoring (primarily JMX) related methods
-
-    /**
-     * Provides the name under which the pool has been registered with the
-     * platform MBean server or <code>null</code> if the pool has not been
-     * registered.
-     * @return the JMX name
-     */
-    public final ObjectName getJmxName() {
-        return objectName;
-    }
-
-    /**
-     * Provides the stack trace for the call that created this pool. JMX
-     * registration may trigger a memory leak so it is important that pools are
-     * deregistered when no longer used by calling the {@link #close()} method.
-     * This method is provided to assist with identifying code that creates but
-     * does not close it thereby creating a memory leak.
-     * @return pool creation stack trace
-     */
-    public final String getCreationStackTrace() {
-        return creationStackTrace;
-    }
-
-    /**
-     * The total number of objects successfully borrowed from this pool over the
-     * lifetime of the pool.
-     * @return the borrowed object count
-     */
-    public final long getBorrowedCount() {
-        return borrowedCount.get();
-    }
-
-    /**
-     * The total number of objects returned to this pool over the lifetime of
-     * the pool. This excludes attempts to return the same object multiple
-     * times.
-     * @return the returned object count
-     */
-    public final long getReturnedCount() {
-        return returnedCount.get();
-    }
-
-    /**
-     * The total number of objects created for this pool over the lifetime of
-     * the pool.
-     * @return the created object count
-     */
-    public final long getCreatedCount() {
-        return createdCount.get();
-    }
-
-    /**
-     * The total number of objects destroyed by this pool over the lifetime of
-     * the pool.
-     * @return the destroyed object count
-     */
-    public final long getDestroyedCount() {
-        return destroyedCount.get();
-    }
-
-    /**
-     * The total number of objects destroyed by the evictor associated with this
-     * pool over the lifetime of the pool.
-     * @return the evictor destroyed object count
-     */
-    public final long getDestroyedByEvictorCount() {
-        return destroyedByEvictorCount.get();
-    }
-
-    /**
-     * The total number of objects destroyed by this pool as a result of failing
-     * validation during <code>borrowObject()</code> over the lifetime of the
-     * pool.
-     * @return validation destroyed object count
-     */
-    public final long getDestroyedByBorrowValidationCount() {
-        return destroyedByBorrowValidationCount.get();
-    }
-
-    /**
-     * The mean time objects are active for based on the last {@link
-     * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool.
-     * @return mean time an object has been checked out from the pool among
-     * recently returned objects
-     */
-    public final long getMeanActiveTimeMillis() {
-        return activeTimes.getMean();
-    }
-
-    /**
-     * The mean time objects are idle for based on the last {@link
-     * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
-     * @return mean time an object has been idle in the pool among recently
-     * borrowed objects
-     */
-    public final long getMeanIdleTimeMillis() {
-        return idleTimes.getMean();
-    }
-
-    /**
-     * The mean time threads wait to borrow an object based on the last {@link
-     * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
-     * @return mean time in milliseconds that a recently served thread has had
-     * to wait to borrow an object from the pool
-     */
-    public final long getMeanBorrowWaitTimeMillis() {
-        return waitTimes.getMean();
-    }
-
-    /**
-     * The maximum time a thread has waited to borrow objects from the pool.
-     * @return maximum wait time in milliseconds since the pool was created
-     */
-    public final long getMaxBorrowWaitTimeMillis() {
-        return maxBorrowWaitTimeMillis.get();
-    }
-
-    /**
-     * The number of instances currently idle in this pool.
-     * @return count of instances available for checkout from the pool
-     */
-    public abstract int getNumIdle();
-
-    /**
-     * The listener used (if any) to receive notifications of exceptions
-     * unavoidably swallowed by the pool.
-     *
-     * @return The listener or <code>null</code> for no listener
-     */
-    public final SwallowedExceptionListener getSwallowedExceptionListener() {
-        return swallowedExceptionListener;
-    }
-
-    /**
-     * The listener used (if any) to receive notifications of exceptions
-     * unavoidably swallowed by the pool.
-     *
-     * @param swallowedExceptionListener    The listener or <code>null</code>
-     *                                      for no listener
-     */
-    public final void setSwallowedExceptionListener(
-            final SwallowedExceptionListener swallowedExceptionListener) {
-        this.swallowedExceptionListener = swallowedExceptionListener;
-    }
-
-    /**
-     * Swallows an exception and notifies the configured listener for swallowed
-     * exceptions queue.
-     *
-     * @param swallowException exception to be swallowed
-     */
-    final void swallowException(final Exception swallowException) {
-        final SwallowedExceptionListener listener = getSwallowedExceptionListener();
-
-        if (listener == null) {
-            return;
-        }
-
-        try {
-            listener.onSwallowException(swallowException);
-        } catch (final VirtualMachineError e) {
-            throw e;
-        } catch (final Throwable t) {
-            // Ignore. Enjoy the irony.
-        }
-    }
-
-    /**
-     * Updates statistics after an object is borrowed from the pool.
-     * @param p object borrowed from the pool
-     * @param waitTime time (in milliseconds) that the borrowing thread had to wait
-     */
-    final void updateStatsBorrow(final PooledObject<T> p, final long waitTime) {
-        borrowedCount.incrementAndGet();
-        idleTimes.add(p.getIdleTimeMillis());
-        waitTimes.add(waitTime);
-
-        // lock-free optimistic-locking maximum
-        long currentMax;
-        do {
-            currentMax = maxBorrowWaitTimeMillis.get();
-            if (currentMax >= waitTime) {
-                break;
-            }
-        } while (!maxBorrowWaitTimeMillis.compareAndSet(currentMax, waitTime));
-    }
-
-    /**
-     * Updates statistics after an object is returned to the pool.
-     * @param activeTime the amount of time (in milliseconds) that the returning
-     * object was checked out
-     */
-    final void updateStatsReturn(final long activeTime) {
-        returnedCount.incrementAndGet();
-        activeTimes.add(activeTime);
-    }
-
-    /**
-     * Marks the object as returning to the pool.
-     * @param pooledObject instance to return to the keyed pool
-     */
-    protected void markReturningState(final PooledObject<T> pooledObject) {
-        synchronized(pooledObject) {
-            final PooledObjectState state = pooledObject.getState();
-            if (state != PooledObjectState.ALLOCATED) {
-                throw new IllegalStateException(
-                        "Object has already been returned to this pool or is invalid");
-            }
-            pooledObject.markReturning(); // Keep from being marked abandoned
-        }
-    }
-
-    /**
-     * Unregisters this pool's MBean.
-     */
-    final void jmxUnregister() {
-        if (objectName != null) {
-            try {
-                ManagementFactory.getPlatformMBeanServer().unregisterMBean(
-                        objectName);
-            } catch (final MBeanRegistrationException | InstanceNotFoundException e) {
-                swallowException(e);
-            }
-        }
-    }
-
-    /**
-     * Registers the pool with the platform MBean server.
-     * The registered name will be
-     * <code>jmxNameBase + jmxNamePrefix + i</code> where i is the least
-     * integer greater than or equal to 1 such that the name is not already
-     * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException
-     * returning null.
-     *
-     * @param config Pool configuration
-     * @param jmxNameBase default base JMX name for this pool
-     * @param jmxNamePrefix name prefix
-     * @return registered ObjectName, null if registration fails
-     */
-    private ObjectName jmxRegister(final BaseObjectPoolConfig<T> config,
-            final String jmxNameBase, String jmxNamePrefix) {
-        ObjectName newObjectName = null;
-        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-        int i = 1;
-        boolean registered = false;
-        String base = config.getJmxNameBase();
-        if (base == null) {
-            base = jmxNameBase;
-        }
-        while (!registered) {
-            try {
-                ObjectName objName;
-                // Skip the numeric suffix for the first pool in case there is
-                // only one so the names are cleaner.
-                if (i == 1) {
-                    objName = new ObjectName(base + jmxNamePrefix);
-                } else {
-                    objName = new ObjectName(base + jmxNamePrefix + i);
-                }
-                mbs.registerMBean(this, objName);
-                newObjectName = objName;
-                registered = true;
-            } catch (final MalformedObjectNameException e) {
-                if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals(
-                        jmxNamePrefix) && jmxNameBase.equals(base)) {
-                    // Shouldn't happen. Skip registration if it does.
-                    registered = true;
-                } else {
-                    // Must be an invalid name. Use the defaults instead.
-                    jmxNamePrefix =
-                            BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX;
-                    base = jmxNameBase;
-                }
-            } catch (final InstanceAlreadyExistsException e) {
-                // Increment the index and try again
-                i++;
-            } catch (final MBeanRegistrationException | NotCompliantMBeanException e) {
-                // Shouldn't happen. Skip registration if it does.
-                registered = true;
-            }
-        }
-        return newObjectName;
-    }
-
-    /**
-     * Gets the stack trace of an exception as a string.
-     * @param e exception to trace
-     * @return exception stack trace as a string
-     */
-    private String getStackTrace(final Exception e) {
-        // Need the exception in string form to prevent the retention of
-        // references to classes in the stack trace that could trigger a memory
-        // leak in a container environment.
-        final Writer w = new StringWriter();
-        final PrintWriter pw = new PrintWriter(w);
-        e.printStackTrace(pw);
-        return w.toString();
-    }
-
-    // Inner classes
-
-    /**
-     * The idle object evictor {@link TimerTask}.
-     *
-     * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
-     */
-    class Evictor implements Runnable {
-
-        private ScheduledFuture<?> scheduledFuture;
-
-        /**
-         * Run pool maintenance.  Evict objects qualifying for eviction and then
-         * ensure that the minimum number of idle instances are available.
-         * Since the Timer that invokes Evictors is shared for all Pools but
-         * pools may exist in different class loaders, the Evictor ensures that
-         * any actions taken are under the class loader of the factory
-         * associated with the pool.
-         */
-        @Override
-        public void run() {
-            final ClassLoader savedClassLoader =
-                    Thread.currentThread().getContextClassLoader();
-            try {
-                if (factoryClassLoader != null) {
-                    // Set the class loader for the factory
-                    final ClassLoader cl = factoryClassLoader.get();
-                    if (cl == null) {
-                        // The pool has been dereferenced and the class loader
-                        // GC'd. Cancel this timer so the pool can be GC'd as
-                        // well.
-                        cancel();
-                        return;
-                    }
-                    Thread.currentThread().setContextClassLoader(cl);
-                }
-
-                // Evict from the pool
-                try {
-                    evict();
-                } catch(final Exception e) {
-                    swallowException(e);
-                } catch(final OutOfMemoryError oome) {
-                    // Log problem but give evictor thread a chance to continue
-                    // in case error is recoverable
-                    oome.printStackTrace(System.err);
-                }
-                // Re-create idle instances.
-                try {
-                    ensureMinIdle();
-                } catch (final Exception e) {
-                    swallowException(e);
-                }
-            } finally {
-                // Restore the previous CCL
-                Thread.currentThread().setContextClassLoader(savedClassLoader);
-            }
-        }
-
-
-        void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) {
-            this.scheduledFuture = scheduledFuture;
-        }
-
-
-        void cancel() {
-            scheduledFuture.cancel(false);
-        }
-    }
-
-    /**
-     * Maintains a cache of values for a single metric and reports
-     * statistics on the cached values.
-     */
-    private class StatsStore {
-
-        private final AtomicLong values[];
-        private final int size;
-        private int index;
-
-        /**
-         * Create a StatsStore with the given cache size.
-         *
-         * @param size number of values to maintain in the cache.
-         */
-        public StatsStore(final int size) {
-            this.size = size;
-            values = new AtomicLong[size];
-            for (int i = 0; i < size; i++) {
-                values[i] = new AtomicLong(-1);
-            }
-        }
-
-        /**
-         * Adds a value to the cache.  If the cache is full, one of the
-         * existing values is replaced by the new value.
-         *
-         * @param value new value to add to the cache.
-         */
-        public synchronized void add(final long value) {
-            values[index].set(value);
-            index++;
-            if (index == size) {
-                index = 0;
-            }
-        }
-
-        /**
-         * Returns the mean of the cached values.
-         *
-         * @return the mean of the cache, truncated to long
-         */
-        public long getMean() {
-            double result = 0;
-            int counter = 0;
-            for (int i = 0; i < size; i++) {
-                final long value = values[i].get();
-                if (value != -1) {
-                    counter++;
-                    result = result * ((counter - 1) / (double) counter) +
-                            value/(double) counter;
-                }
-            }
-            return (long) result;
-        }
-
-        @Override
-        public String toString() {
-            final StringBuilder builder = new StringBuilder();
-            builder.append("StatsStore [values=");
-            builder.append(Arrays.toString(values));
-            builder.append(", size=");
-            builder.append(size);
-            builder.append(", index=");
-            builder.append(index);
-            builder.append("]");
-            return builder.toString();
-        }
-    }
-
-    /**
-     * The idle object eviction iterator. Holds a reference to the idle objects.
-     */
-    class EvictionIterator implements Iterator<PooledObject<T>> {
-
-        private final Deque<PooledObject<T>> idleObjects;
-        private final Iterator<PooledObject<T>> idleObjectIterator;
-
-        /**
-         * Create an EvictionIterator for the provided idle instance deque.
-         * @param idleObjects underlying deque
-         */
-        EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
-            this.idleObjects = idleObjects;
-
-            if (getLifo()) {
-                idleObjectIterator = idleObjects.descendingIterator();
-            } else {
-                idleObjectIterator = idleObjects.iterator();
-            }
-        }
-
-        /**
-         * Returns the idle object deque referenced by this iterator.
-         * @return the idle object deque
-         */
-        public Deque<PooledObject<T>> getIdleObjects() {
-            return idleObjects;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean hasNext() {
-            return idleObjectIterator.hasNext();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public PooledObject<T> next() {
-            return idleObjectIterator.next();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void remove() {
-            idleObjectIterator.remove();
-        }
-
-    }
-
-    /**
-     * Wrapper for objects under management by the pool.
-     *
-     * GenericObjectPool and GenericKeyedObjectPool maintain references to all
-     * objects under management using maps keyed on the objects. This wrapper
-     * class ensures that objects can work as hash keys.
-     *
-     * @param <T> type of objects in the pool
-     */
-    static class IdentityWrapper<T> {
-        /** Wrapped object */
-        private final T instance;
-
-        /**
-         * Create a wrapper for an instance.
-         *
-         * @param instance object to wrap
-         */
-        public IdentityWrapper(final T instance) {
-            this.instance = instance;
-        }
-
-        @Override
-        public int hashCode() {
-            return System.identityHashCode(instance);
-        }
-
-        @Override
-        @SuppressWarnings("rawtypes")
-        public boolean equals(final Object other) {
-            return  other instanceof IdentityWrapper &&
-                    ((IdentityWrapper) other).instance == instance;
-        }
-
-        /**
-         * @return the wrapped object
-         */
-        public T getObject() {
-            return instance;
-        }
-
-        @Override
-        public String toString() {
-            final StringBuilder builder = new StringBuilder();
-            builder.append("IdentityWrapper [instance=");
-            builder.append(instance);
-            builder.append("]");
-            return builder.toString();
-        }
-    }
-
-    @Override
-    protected void toStringAppendFields(final StringBuilder builder) {
-        builder.append("maxTotal=");
-        builder.append(maxTotal);
-        builder.append(", blockWhenExhausted=");
-        builder.append(blockWhenExhausted);
-        builder.append(", maxWaitMillis=");
-        builder.append(maxWaitMillis);
-        builder.append(", lifo=");
-        builder.append(lifo);
-        builder.append(", fairness=");
-        builder.append(fairness);
-        builder.append(", testOnCreate=");
-        builder.append(testOnCreate);
-        builder.append(", testOnBorrow=");
-        builder.append(testOnBorrow);
-        builder.append(", testOnReturn=");
-        builder.append(testOnReturn);
-        builder.append(", testWhileIdle=");
-        builder.append(testWhileIdle);
-        builder.append(", timeBetweenEvictionRunsMillis=");
-        builder.append(timeBetweenEvictionRunsMillis);
-        builder.append(", numTestsPerEvictionRun=");
-        builder.append(numTestsPerEvictionRun);
-        builder.append(", minEvictableIdleTimeMillis=");
-        builder.append(minEvictableIdleTimeMillis);
-        builder.append(", softMinEvictableIdleTimeMillis=");
-        builder.append(softMinEvictableIdleTimeMillis);
-        builder.append(", evictionPolicy=");
-        builder.append(evictionPolicy);
-        builder.append(", closeLock=");
-        builder.append(closeLock);
-        builder.append(", closed=");
-        builder.append(closed);
-        builder.append(", evictionLock=");
-        builder.append(evictionLock);
-        builder.append(", evictor=");
-        builder.append(evictor);
-        builder.append(", evictionIterator=");
-        builder.append(evictionIterator);
-        builder.append(", factoryClassLoader=");
-        builder.append(factoryClassLoader);
-        builder.append(", oname=");
-        builder.append(objectName);
-        builder.append(", creationStackTrace=");
-        builder.append(creationStackTrace);
-        builder.append(", borrowedCount=");
-        builder.append(borrowedCount);
-        builder.append(", returnedCount=");
-        builder.append(returnedCount);
-        builder.append(", createdCount=");
-        builder.append(createdCount);
-        builder.append(", destroyedCount=");
-        builder.append(destroyedCount);
-        builder.append(", destroyedByEvictorCount=");
-        builder.append(destroyedByEvictorCount);
-        builder.append(", destroyedByBorrowValidationCount=");
-        builder.append(destroyedByBorrowValidationCount);
-        builder.append(", activeTimes=");
-        builder.append(activeTimes);
-        builder.append(", idleTimes=");
-        builder.append(idleTimes);
-        builder.append(", waitTimes=");
-        builder.append(waitTimes);
-        builder.append(", maxBorrowWaitTimeMillis=");
-        builder.append(maxBorrowWaitTimeMillis);
-        builder.append(", swallowedExceptionListener=");
-        builder.append(swallowedExceptionListener);
-    }
-
-
-}
+/*
+ * 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 java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import org.apache.commons.pool2.BaseObject;
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.PooledObjectState;
+import org.apache.commons.pool2.SwallowedExceptionListener;
+
+/**
+ * Base class that provides common functionality for {@link GenericObjectPool}
+ * and {@link GenericKeyedObjectPool}. The primary reason this class exists is
+ * reduce code duplication between the two pool implementations.
+ *
+ * @param <T> Type of element pooled in this pool.
+ *
+ * This class is intended to be thread-safe.
+ *
+ * @since 2.0
+ */
+public abstract class BaseGenericObjectPool<T> extends BaseObject {
+
+    // Constants
+    /**
+     * The size of the caches used to store historical data for some attributes
+     * so that rolling means may be calculated.
+     */
+    public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100;
+
+    private static final String EVICTION_POLICY_TYPE_NAME = EvictionPolicy.class.getName();
+
+    // Configuration attributes
+    private volatile int maxTotal =
+            GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
+    private volatile boolean blockWhenExhausted =
+            BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
+    private volatile long maxWaitMillis =
+            BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
+    private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
+    private final boolean fairness;
+    private volatile boolean testOnCreate =
+            BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
+    private volatile boolean testOnBorrow =
+            BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
+    private volatile boolean testOnReturn =
+            BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
+    private volatile boolean testWhileIdle =
+            BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
+    private volatile long timeBetweenEvictionRunsMillis =
+            BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
+    private volatile int numTestsPerEvictionRun =
+            BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
+    private volatile long minEvictableIdleTimeMillis =
+            BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+    private volatile long softMinEvictableIdleTimeMillis =
+            BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
+    private volatile EvictionPolicy<T> evictionPolicy;
+    private volatile long evictorShutdownTimeoutMillis =
+            BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
+
+
+    // Internal (primarily state) attributes
+    final Object closeLock = new Object();
+    volatile boolean closed = false;
+    final Object evictionLock = new Object();
+    private Evictor evictor = null; // @GuardedBy("evictionLock")
+    EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
+    /*
+     * Class loader for evictor thread to use since, in a JavaEE or similar
+     * environment, the context class loader for the evictor thread may not have
+     * visibility of the correct factory. See POOL-161. Uses a weak reference to
+     * avoid potential memory leaks if the Pool is discarded rather than closed.
+     */
+    private final WeakReference<ClassLoader> factoryClassLoader;
+
+
+    // Monitoring (primarily JMX) attributes
+    private final ObjectName objectName;
+    private final String creationStackTrace;
+    private final AtomicLong borrowedCount = new AtomicLong(0);
+    private final AtomicLong returnedCount = new AtomicLong(0);
+    final AtomicLong createdCount = new AtomicLong(0);
+    final AtomicLong destroyedCount = new AtomicLong(0);
+    final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
+    final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
+    private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
+    private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
+    private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
+    private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L);
+    private volatile SwallowedExceptionListener swallowedExceptionListener = null;
+
+
+    /**
+     * Handles JMX registration (if required) and the initialization required for
+     * monitoring.
+     *
+     * @param config        Pool configuration
+     * @param jmxNameBase   The default base JMX name for the new pool unless
+     *                      overridden by the config
+     * @param jmxNamePrefix Prefix to be used for JMX name for the new pool
+     */
+    public BaseGenericObjectPool(final BaseObjectPoolConfig<T> config,
+            final String jmxNameBase, final String jmxNamePrefix) {
+        if (config.getJmxEnabled()) {
+            this.objectName = jmxRegister(config, jmxNameBase, jmxNamePrefix);
+        } else {
+            this.objectName = null;
+        }
+
+        // Populate the creation stack trace
+        this.creationStackTrace = getStackTrace(new Exception());
+
+        // save the current TCCL (if any) to be used later by the evictor Thread
+        final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            factoryClassLoader = null;
+        } else {
+            factoryClassLoader = new WeakReference<>(cl);
+        }
+
+        fairness = config.getFairness();
+    }
+
+
+    /**
+     * Returns the maximum number of objects that can be allocated by the pool
+     * (checked out to clients, or idle awaiting checkout) at a given time. When
+     * negative, there is no limit to the number of objects that can be
+     * managed by the pool at one time.
+     *
+     * @return the cap on the total number of object instances managed by the
+     *         pool.
+     *
+     * @see #setMaxTotal
+     */
+    public final int getMaxTotal() {
+        return maxTotal;
+    }
+
+    /**
+     * Sets the cap on the number of objects that can be allocated by the pool
+     * (checked out to clients, or idle awaiting checkout) at a given time. Use
+     * a negative value for no limit.
+     *
+     * @param maxTotal  The cap on the total number of object instances managed
+     *                  by the pool. Negative values mean that there is no limit
+     *                  to the number of objects allocated by the pool.
+     *
+     * @see #getMaxTotal
+     */
+    public final void setMaxTotal(final int maxTotal) {
+        this.maxTotal = maxTotal;
+    }
+
+    /**
+     * Returns whether to block when the <code>borrowObject()</code> method is
+     * invoked when the pool is exhausted (the maximum number of "active"
+     * objects has been reached).
+     *
+     * @return <code>true</code> if <code>borrowObject()</code> should block
+     *         when the pool is exhausted
+     *
+     * @see #setBlockWhenExhausted
+     */
+    public final boolean getBlockWhenExhausted() {
+        return blockWhenExhausted;
+    }
+
+    /**
+     * Sets whether to block when the <code>borrowObject()</code> method is
+     * invoked when the pool is exhausted (the maximum number of "active"
+     * objects has been reached).
+     *
+     * @param blockWhenExhausted    <code>true</code> if
+     *                              <code>borrowObject()</code> should block
+     *                              when the pool is exhausted
+     *
+     * @see #getBlockWhenExhausted
+     */
+    public final void setBlockWhenExhausted(final boolean blockWhenExhausted) {
+        this.blockWhenExhausted = blockWhenExhausted;
+    }
+
+    protected void setConfig(final BaseObjectPoolConfig<T> conf) {
+        setLifo(conf.getLifo());
+        setMaxWaitMillis(conf.getMaxWaitMillis());
+        setBlockWhenExhausted(conf.getBlockWhenExhausted());
+        setTestOnCreate(conf.getTestOnCreate());
+        setTestOnBorrow(conf.getTestOnBorrow());
+        setTestOnReturn(conf.getTestOnReturn());
+        setTestWhileIdle(conf.getTestWhileIdle());
+        setNumTestsPerEvictionRun(conf.getNumTestsPerEvictionRun());
+        setMinEvictableIdleTimeMillis(conf.getMinEvictableIdleTimeMillis());
+        setTimeBetweenEvictionRunsMillis(conf.getTimeBetweenEvictionRunsMillis());
+        setSoftMinEvictableIdleTimeMillis(conf.getSoftMinEvictableIdleTimeMillis());
+        final EvictionPolicy<T> policy = conf.getEvictionPolicy();
+        if (policy == null) {
+            // Use the class name (pre-2.6.0 compatible)
+            setEvictionPolicyClassName(conf.getEvictionPolicyClassName());
+        } else {
+            // Otherwise, use the class (2.6.0 feature)
+            setEvictionPolicy(policy);
+        }
+        setEvictorShutdownTimeoutMillis(conf.getEvictorShutdownTimeoutMillis());
+    }
+
+    /**
+     * Returns the maximum amount of time (in milliseconds) the
+     * <code>borrowObject()</code> method should block before throwing an
+     * exception when the pool is exhausted and
+     * {@link #getBlockWhenExhausted} is true. When less than 0, the
+     * <code>borrowObject()</code> method may block indefinitely.
+     *
+     * @return the maximum number of milliseconds <code>borrowObject()</code>
+     *         will block.
+     *
+     * @see #setMaxWaitMillis
+     * @see #setBlockWhenExhausted
+     */
+    public final long getMaxWaitMillis() {
+        return maxWaitMillis;
+    }
+
+    /**
+     * Sets the maximum amount of time (in milliseconds) the
+     * <code>borrowObject()</code> method should block before throwing an
+     * exception when the pool is exhausted and
+     * {@link #getBlockWhenExhausted} is true. When less than 0, the
+     * <code>borrowObject()</code> method may block indefinitely.
+     *
+     * @param maxWaitMillis the maximum number of milliseconds
+     *                      <code>borrowObject()</code> will block or negative
+     *                      for indefinitely.
+     *
+     * @see #getMaxWaitMillis
+     * @see #setBlockWhenExhausted
+     */
+    public final void setMaxWaitMillis(final long maxWaitMillis) {
+        this.maxWaitMillis = maxWaitMillis;
+    }
+
+    /**
+     * Returns whether the pool has LIFO (last in, first out) behaviour with
+     * respect to idle objects - always returning the most recently used object
+     * from the pool, or as a FIFO (first in, first out) queue, where the pool
+     * always returns the oldest object in the idle object pool.
+     *
+     * @return <code>true</code> if the pool is configured with LIFO behaviour
+     *         or <code>false</code> if the pool is configured with FIFO
+     *         behaviour
+     *
+     * @see #setLifo
+     */
+    public final boolean getLifo() {
+        return lifo;
+    }
+
+    /**
+     * Returns whether or not the pool serves threads waiting to borrow objects fairly.
+     * True means that waiting threads are served as if waiting in a FIFO queue.
+     *
+     * @return <code>true</code> if waiting threads are to be served
+     *             by the pool in arrival order
+     */
+    public final boolean getFairness() {
+        return fairness;
+    }
+
+    /**
+     * Sets whether the pool has LIFO (last in, first out) behaviour with
+     * respect to idle objects - always returning the most recently used object
+     * from the pool, or as a FIFO (first in, first out) queue, where the pool
+     * always returns the oldest object in the idle object pool.
+     *
+     * @param lifo  <code>true</code> if the pool is to be configured with LIFO
+     *              behaviour or <code>false</code> if the pool is to be
+     *              configured with FIFO behaviour
+     *
+     * @see #getLifo()
+     */
+    public final void setLifo(final boolean lifo) {
+        this.lifo = lifo;
+    }
+
+    /**
+     * Returns whether objects created for the pool will be validated before
+     * being returned from the <code>borrowObject()</code> method. Validation is
+     * performed by the <code>validateObject()</code> method of the factory
+     * associated with the pool. If the object fails to validate, then
+     * <code>borrowObject()</code> will fail.
+     *
+     * @return <code>true</code> if newly created objects are validated before
+     *         being returned from the <code>borrowObject()</code> method
+     *
+     * @see #setTestOnCreate
+     *
+     * @since 2.2
+     */
+    public final boolean getTestOnCreate() {
+        return testOnCreate;
+    }
+
+    /**
+     * Sets whether objects created for the pool will be validated before
+     * being returned from the <code>borrowObject()</code> method. Validation is
+     * performed by the <code>validateObject()</code> method of the factory
+     * associated with the pool. If the object fails to validate, then
+     * <code>borrowObject()</code> will fail.
+     *
+     * @param testOnCreate  <code>true</code> if newly created objects should be
+     *                      validated before being returned from the
+     *                      <code>borrowObject()</code> method
+     *
+     * @see #getTestOnCreate
+     *
+     * @since 2.2
+     */
+    public final void setTestOnCreate(final boolean testOnCreate) {
+        this.testOnCreate = testOnCreate;
+    }
+
+    /**
+     * Returns whether objects borrowed from the pool will be validated before
+     * being returned from the <code>borrowObject()</code> method. Validation is
+     * performed by the <code>validateObject()</code> method of the factory
+     * associated with the pool. If the object fails to validate, it will be
+     * removed from the pool and destroyed, and a new attempt will be made to
+     * borrow an object from the pool.
+     *
+     * @return <code>true</code> if objects are validated before being returned
+     *         from the <code>borrowObject()</code> method
+     *
+     * @see #setTestOnBorrow
+     */
+    public final boolean getTestOnBorrow() {
+        return testOnBorrow;
+    }
+
+    /**
+     * Sets whether objects borrowed from the pool will be validated before
+     * being returned from the <code>borrowObject()</code> method. Validation is
+     * performed by the <code>validateObject()</code> method of the factory
+     * associated with the pool. If the object fails to validate, it will be
+     * removed from the pool and destroyed, and a new attempt will be made to
+     * borrow an object from the pool.
+     *
+     * @param testOnBorrow  <code>true</code> if objects should be validated
+     *                      before being returned from the
+     *                      <code>borrowObject()</code> method
+     *
+     * @see #getTestOnBorrow
+     */
+    public final void setTestOnBorrow(final boolean testOnBorrow) {
+        this.testOnBorrow = testOnBorrow;
+    }
+
+    /**
+     * Returns whether objects borrowed from the pool will be validated when
+     * they are returned to the pool via the <code>returnObject()</code> method.
+     * Validation is performed by the <code>validateObject()</code> method of
+     * the factory associated with the pool. Returning objects that fail validation
+     * are destroyed rather then being returned the pool.
+     *
+     * @return <code>true</code> if objects are validated on return to
+     *         the pool via the <code>returnObject()</code> method
+     *
+     * @see #setTestOnReturn
+     */
+    public final boolean getTestOnReturn() {
+        return testOnReturn;
+    }
+
+    /**
+     * Sets whether objects borrowed from the pool will be validated when
+     * they are returned to the pool via the <code>returnObject()</code> method.
+     * Validation is performed by the <code>validateObject()</code> method of
+     * the factory associated with the pool. Returning objects that fail validation
+     * are destroyed rather then being returned the pool.
+     *
+     * @param testOnReturn <code>true</code> if objects are validated on
+     *                     return to the pool via the
+     *                     <code>returnObject()</code> method
+     *
+     * @see #getTestOnReturn
+     */
+    public final void setTestOnReturn(final boolean testOnReturn) {
+        this.testOnReturn = testOnReturn;
+    }
+
+    /**
+     * Returns whether objects sitting idle in the pool will be validated by the
+     * idle object evictor (if any - see
+     * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
+     * by the <code>validateObject()</code> method of the factory associated
+     * with the pool. If the object fails to validate, it will be removed from
+     * the pool and destroyed.
+     *
+     * @return <code>true</code> if objects will be validated by the evictor
+     *
+     * @see #setTestWhileIdle
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final boolean getTestWhileIdle() {
+        return testWhileIdle;
+    }
+
+    /**
+     * Returns whether objects sitting idle in the pool will be validated by the
+     * idle object evictor (if any - see
+     * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
+     * by the <code>validateObject()</code> method of the factory associated
+     * with the pool. If the object fails to validate, it will be removed from
+     * the pool and destroyed.  Note that setting this property has no effect
+     * unless the idle object evictor is enabled by setting
+     * <code>timeBetweenEvictionRunsMillis</code> to a positive value.
+     *
+     * @param testWhileIdle
+     *            <code>true</code> so objects will be validated by the evictor
+     *
+     * @see #getTestWhileIdle
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final void setTestWhileIdle(final boolean testWhileIdle) {
+        this.testWhileIdle = testWhileIdle;
+    }
+
+    /**
+     * Returns the number of milliseconds to sleep between runs of the idle
+     * object evictor thread. When non-positive, no idle object evictor thread
+     * will be run.
+     *
+     * @return number of milliseconds to sleep between evictor runs
+     *
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final long getTimeBetweenEvictionRunsMillis() {
+        return timeBetweenEvictionRunsMillis;
+    }
+
+    /**
+     * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
+     * <ul>
+     * <li>When positive, the idle object evictor thread starts.</li>
+     * <li>When non-positive, no idle object evictor thread runs.</li>
+     * </ul>
+     *
+     * @param timeBetweenEvictionRunsMillis
+     *            number of milliseconds to sleep between evictor runs
+     *
+     * @see #getTimeBetweenEvictionRunsMillis
+     */
+    public final void setTimeBetweenEvictionRunsMillis(
+            final long timeBetweenEvictionRunsMillis) {
+        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+        startEvictor(timeBetweenEvictionRunsMillis);
+    }
+
+    /**
+     * Returns the maximum number of objects to examine during each run (if any)
+     * of the idle object evictor thread. When positive, the number of tests
+     * performed for a run will be the minimum of the configured value and the
+     * number of idle instances in the pool. When negative, the number of tests
+     * performed will be <code>ceil({@link #getNumIdle}/
+     * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
+     * value is <code>-n</code> roughly one nth of the idle objects will be
+     * tested per run.
+     *
+     * @return max number of objects to examine during each evictor run
+     *
+     * @see #setNumTestsPerEvictionRun
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final int getNumTestsPerEvictionRun() {
+        return numTestsPerEvictionRun;
+    }
+
+    /**
+     * Sets the maximum number of objects to examine during each run (if any)
+     * of the idle object evictor thread. When positive, the number of tests
+     * performed for a run will be the minimum of the configured value and the
+     * number of idle instances in the pool. When negative, the number of tests
+     * performed will be <code>ceil({@link #getNumIdle}/
+     * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
+     * value is <code>-n</code> roughly one nth of the idle objects will be
+     * tested per run.
+     *
+     * @param numTestsPerEvictionRun
+     *            max number of objects to examine during each evictor run
+     *
+     * @see #getNumTestsPerEvictionRun
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
+        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
+    }
+
+    /**
+     * Returns the minimum amount of time an object may sit idle in the pool
+     * before it is eligible for eviction by the idle object evictor (if any -
+     * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
+     * no objects will be evicted from the pool due to idle time alone.
+     *
+     * @return minimum amount of time an object may sit idle in the pool before
+     *         it is eligible for eviction
+     *
+     * @see #setMinEvictableIdleTimeMillis
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final long getMinEvictableIdleTimeMillis() {
+        return minEvictableIdleTimeMillis;
+    }
+
+    /**
+     * Sets the minimum amount of time an object may sit idle in the pool
+     * before it is eligible for eviction by the idle object evictor (if any -
+     * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
+     * no objects will be evicted from the pool due to idle time alone.
+     *
+     * @param minEvictableIdleTimeMillis
+     *            minimum amount of time an object may sit idle in the pool
+     *            before it is eligible for eviction
+     *
+     * @see #getMinEvictableIdleTimeMillis
+     * @see #setTimeBetweenEvictionRunsMillis
+     */
+    public final void setMinEvictableIdleTimeMillis(
+            final long minEvictableIdleTimeMillis) {
+        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+    }
+
+    /**
+     * Returns the minimum amount of time an object may sit idle in the pool
+     * before it is eligible for eviction by the idle object evictor (if any -
+     * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
+     * with the extra condition that at least <code>minIdle</code> object
+     * instances remain in the pool. This setting is overridden by
+     * {@link #getMinEvictableIdleTimeMillis} (that is, if
+     * {@link #getMinEvictableIdleTimeMillis} is positive, then
+     * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
+     *
+     * @return minimum amount of time an object may sit idle in the pool before
+     *         it is eligible for eviction if minIdle instances are available
+     *
+     * @see #setSoftMinEvictableIdleTimeMillis
+     */
+    public final long getSoftMinEvictableIdleTimeMillis() {
+        return softMinEvictableIdleTimeMillis;
+    }
+
+    /**
+     * Sets the minimum amount of time an object may sit idle in the pool
+     * before it is eligible for eviction by the idle object evictor (if any -
+     * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
+     * with the extra condition that at least <code>minIdle</code> object
+     * instances remain in the pool. This setting is overridden by
+     * {@link #getMinEvictableIdleTimeMillis} (that is, if
+     * {@link #getMinEvictableIdleTimeMillis} is positive, then
+     * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
+     *
+     * @param softMinEvictableIdleTimeMillis
+     *            minimum amount of time an object may sit idle in the pool
+     *            before it is eligible for eviction if minIdle instances are
+     *            available
+     *
+     * @see #getSoftMinEvictableIdleTimeMillis
+     */
+    public final void setSoftMinEvictableIdleTimeMillis(
+            final long softMinEvictableIdleTimeMillis) {
+        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
+    }
+
+    /**
+     * Returns the name of the {@link EvictionPolicy} implementation that is
+     * used by this pool.
+     *
+     * @return  The fully qualified class name of the {@link EvictionPolicy}
+     *
+     * @see #setEvictionPolicyClassName(String)
+     */
+    public final String getEvictionPolicyClassName() {
+        return evictionPolicy.getClass().getName();
+    }
+
+    /**
+     * Sets the eviction policy for this pool.
+     *
+     * @param evictionPolicy
+     *            the eviction policy for this pool.
+     * @since 2.6.0
+     */
+    public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
+        this.evictionPolicy = evictionPolicy;
+    }
+
+    /**
+     * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
+     * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy}
+     * interface.
+     *
+     * @param evictionPolicyClassName
+     *            the fully qualified class name of the new eviction policy
+     * @param classLoader
+     *            the class loader to load the given {@code evictionPolicyClassName}.
+     *
+     * @see #getEvictionPolicyClassName()
+     * @since 2.6.0 If loading the class using the given class loader fails, use the class loader for the
+     *        {@link EvictionPolicy} interface.
+     */
+    public final void setEvictionPolicyClassName(final String evictionPolicyClassName, final ClassLoader classLoader) {
+        // Getting epClass here and now best matches the caller's environment
+        final Class<?> epClass = EvictionPolicy.class;
+        final ClassLoader epClassLoader = epClass.getClassLoader();
+        try {
+            try {
+                setEvictionPolicy(evictionPolicyClassName, classLoader);
+            } catch (final ClassCastException | ClassNotFoundException e) {
+                setEvictionPolicy(evictionPolicyClassName, epClassLoader);
+            }
+        } catch (final ClassCastException e) {
+            throw new IllegalArgumentException("Class " + evictionPolicyClassName + " from class loaders ["
+                    + classLoader + ", " + epClassLoader + "] do not implement " + EVICTION_POLICY_TYPE_NAME);
+        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
+                | InvocationTargetException | NoSuchMethodException e) {
+            final String exMessage = "Unable to create " + EVICTION_POLICY_TYPE_NAME + " instance of type "
+                    + evictionPolicyClassName;
+            throw new IllegalArgumentException(exMessage, e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void setEvictionPolicy(final String className, final ClassLoader classLoader)
+            throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        final Class<?> clazz = Class.forName(className, true, classLoader);
+        final Object policy = clazz.getConstructor().newInstance();
+        this.evictionPolicy = (EvictionPolicy<T>) policy;
+    }
+
+    /**
+     * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
+     * load the class using the thread context class loader. If that fails, the use the class loader for the
+     * {@link EvictionPolicy} interface.
+     *
+     * @param evictionPolicyClassName
+     *            the fully qualified class name of the new eviction policy
+     *
+     * @see #getEvictionPolicyClassName()
+     * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the
+     *        {@link EvictionPolicy} interface.
+     */
+    public final void setEvictionPolicyClassName(final String evictionPolicyClassName) {
+        setEvictionPolicyClassName(evictionPolicyClassName, Thread.currentThread().getContextClassLoader());
+    }
+
+    /**
+     * Gets the timeout that will be used when waiting for the Evictor to
+     * shutdown if this pool is closed and it is the only pool still using the
+     * the value for the Evictor.
+     *
+     * @return  The timeout in milliseconds that will be used while waiting for
+     *          the Evictor to shut down.
+     */
+    public final long getEvictorShutdownTimeoutMillis() {
+        return evictorShutdownTimeoutMillis;
+    }
+
+    /**
+     * Sets the timeout that will be used when waiting for the Evictor to
+     * shutdown if this pool is closed and it is the only pool still using the
+     * the value for the Evictor.
+     *
+     * @param evictorShutdownTimeoutMillis  the timeout in milliseconds that
+     *                                      will be used while waiting for the
+     *                                      Evictor to shut down.
+     */
+    public final void setEvictorShutdownTimeoutMillis(
+            final long evictorShutdownTimeoutMillis) {
+        this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
+    }
+
+    /**
+     * Closes the pool, destroys the remaining idle objects and, if registered
+     * in JMX, deregisters it.
+     */
+    public abstract void close();
+
+    /**
+     * Has this pool instance been closed.
+     * @return <code>true</code> when this pool has been closed.
+     */
+    public final boolean isClosed() {
+        return closed;
+    }
+
+    /**
+     * <p>Perform <code>numTests</code> idle object eviction tests, evicting
+     * examined objects that meet the criteria for eviction. If
+     * <code>testWhileIdle</code> is true, examined objects are validated
+     * when visited (and removed if invalid); otherwise only objects that
+     * have been idle for more than <code>minEvicableIdleTimeMillis</code>
+     * are removed.</p>
+     *
+     * @throws Exception when there is a problem evicting idle objects.
+     */
+    public abstract void evict() throws Exception;
+
+    /**
+     * Returns the {@link EvictionPolicy} defined for this pool.
+     *
+     * @return the eviction policy
+     * @since 2.4
+     * @since 2.6.0 Changed access from protected to public.
+     */
+    public EvictionPolicy<T> getEvictionPolicy() {
+        return evictionPolicy;
+    }
+
+    /**
+     * Verifies that the pool is open.
+     * @throws IllegalStateException if the pool is closed.
+     */
+    final void assertOpen() throws IllegalStateException {
+        if (isClosed()) {
+            throw new IllegalStateException("Pool not open");
+        }
+    }
+
+    /**
+     * <p>Starts the evictor with the given delay. If there is an evictor
+     * running when this method is called, it is stopped and replaced with a
+     * new evictor with the specified delay.</p>
+     *
+     * <p>This method needs to be final, since it is called from a constructor.
+     * See POOL-195.</p>
+     *
+     * @param delay time in milliseconds before start and between eviction runs
+     */
+    final void startEvictor(final long delay) {
+        synchronized (evictionLock) {
+            EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
+            evictor = null;
+            evictionIterator = null;
+            if (delay > 0) {
+                evictor = new Evictor();
+                EvictionTimer.schedule(evictor, delay, delay);
+            }
+        }
+    }
+
+    /**
+     * Stops the evictor.
+     */
+    void stopEvitor() {
+        startEvictor(-1L);
+    }
+    /**
+     * Tries to ensure that the configured minimum number of idle instances are
+     * available in the pool.
+     * @throws Exception if an error occurs creating idle instances
+     */
+    abstract void ensureMinIdle() throws Exception;
+
+
+    // Monitoring (primarily JMX) related methods
+
+    /**
+     * Provides the name under which the pool has been registered with the
+     * platform MBean server or <code>null</code> if the pool has not been
+     * registered.
+     * @return the JMX name
+     */
+    public final ObjectName getJmxName() {
+        return objectName;
+    }
+
+    /**
+     * Provides the stack trace for the call that created this pool. JMX
+     * registration may trigger a memory leak so it is important that pools are
+     * deregistered when no longer used by calling the {@link #close()} method.
+     * This method is provided to assist with identifying code that creates but
+     * does not close it thereby creating a memory leak.
+     * @return pool creation stack trace
+     */
+    public final String getCreationStackTrace() {
+        return creationStackTrace;
+    }
+
+    /**
+     * The total number of objects successfully borrowed from this pool over the
+     * lifetime of the pool.
+     * @return the borrowed object count
+     */
+    public final long getBorrowedCount() {
+        return borrowedCount.get();
+    }
+
+    /**
+     * The total number of objects returned to this pool over the lifetime of
+     * the pool. This excludes attempts to return the same object multiple
+     * times.
+     * @return the returned object count
+     */
+    public final long getReturnedCount() {
+        return returnedCount.get();
+    }
+
+    /**
+     * The total number of objects created for this pool over the lifetime of
+     * the pool.
+     * @return the created object count
+     */
+    public final long getCreatedCount() {
+        return createdCount.get();
+    }
+
+    /**
+     * The total number of objects destroyed by this pool over the lifetime of
+     * the pool.
+     * @return the destroyed object count
+     */
+    public final long getDestroyedCount() {
+        return destroyedCount.get();
+    }
+
+    /**
+     * The total number of objects destroyed by the evictor associated with this
+     * pool over the lifetime of the pool.
+     * @return the evictor destroyed object count
+     */
+    public final long getDestroyedByEvictorCount() {
+        return destroyedByEvictorCount.get();
+    }
+
+    /**
+     * The total number of objects destroyed by this pool as a result of failing
+     * validation during <code>borrowObject()</code> over the lifetime of the
+     * pool.
+     * @return validation destroyed object count
+     */
+    public final long getDestroyedByBorrowValidationCount() {
+        return destroyedByBorrowValidationCount.get();
+    }
+
+    /**
+     * The mean time objects are active for based on the last {@link
+     * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool.
+     * @return mean time an object has been checked out from the pool among
+     * recently returned objects
+     */
+    public final long getMeanActiveTimeMillis() {
+        return activeTimes.getMean();
+    }
+
+    /**
+     * The mean time objects are idle for based on the last {@link
+     * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
+     * @return mean time an object has been idle in the pool among recently
+     * borrowed objects
+     */
+    public final long getMeanIdleTimeMillis() {
+        return idleTimes.getMean();
+    }
+
+    /**
+     * The mean time threads wait to borrow an object based on the last {@link
+     * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
+     * @return mean time in milliseconds that a recently served thread has had
+     * to wait to borrow an object from the pool
+     */
+    public final long getMeanBorrowWaitTimeMillis() {
+        return waitTimes.getMean();
+    }
+
+    /**
+     * The maximum time a thread has waited to borrow objects from the pool.
+     * @return maximum wait time in milliseconds since the pool was created
+     */
+    public final long getMaxBorrowWaitTimeMillis() {
+        return maxBorrowWaitTimeMillis.get();
+    }
+
+    /**
+     * The number of instances currently idle in this pool.
+     * @return count of instances available for checkout from the pool
+     */
+    public abstract int getNumIdle();
+
+    /**
+     * The listener used (if any) to receive notifications of exceptions
+     * unavoidably swallowed by the pool.
+     *
+     * @return The listener or <code>null</code> for no listener
+     */
+    public final SwallowedExceptionListener getSwallowedExceptionListener() {
+        return swallowedExceptionListener;
+    }
+
+    /**
+     * The listener used (if any) to receive notifications of exceptions
+     * unavoidably swallowed by the pool.
+     *
+     * @param swallowedExceptionListener    The listener or <code>null</code>
+     *                                      for no listener
+     */
+    public final void setSwallowedExceptionListener(
+            final SwallowedExceptionListener swallowedExceptionListener) {
+        this.swallowedExceptionListener = swallowedExceptionListener;
+    }
+
+    /**
+     * Swallows an exception and notifies the configured listener for swallowed
+     * exceptions queue.
+     *
+     * @param swallowException exception to be swallowed
+     */
+    final void swallowException(final Exception swallowException) {
+        final SwallowedExceptionListener listener = getSwallowedExceptionListener();
+
+        if (listener == null) {
+            return;
+        }
+
+        try {
+            listener.onSwallowException(swallowException);
+        } catch (final VirtualMachineError e) {
+            throw e;
+        } catch (final Throwable t) {
+            // Ignore. Enjoy the irony.
+        }
+    }
+
+    /**
+     * Updates statistics after an object is borrowed from the pool.
+     * @param p object borrowed from the pool
+     * @param waitTime time (in milliseconds) that the borrowing thread had to wait
+     */
+    final void updateStatsBorrow(final PooledObject<T> p, final long waitTime) {
+        borrowedCount.incrementAndGet();
+        idleTimes.add(p.getIdleTimeMillis());
+        waitTimes.add(waitTime);
+
+        // lock-free optimistic-locking maximum
+        long currentMax;
+        do {
+            currentMax = maxBorrowWaitTimeMillis.get();
+            if (currentMax >= waitTime) {
+                break;
+            }
+        } while (!maxBorrowWaitTimeMillis.compareAndSet(currentMax, waitTime));
+    }
+
+    /**
+     * Updates statistics after an object is returned to the pool.
+     * @param activeTime the amount of time (in milliseconds) that the returning
+     * object was checked out
+     */
+    final void updateStatsReturn(final long activeTime) {
+        returnedCount.incrementAndGet();
+        activeTimes.add(activeTime);
+    }
+
+    /**
+     * Marks the object as returning to the pool.
+     * @param pooledObject instance to return to the keyed pool
+     */
+    protected void markReturningState(final PooledObject<T> pooledObject) {
+        synchronized(pooledObject) {
+            final PooledObjectState state = pooledObject.getState();
+            if (state != PooledObjectState.ALLOCATED) {
+                throw new IllegalStateException(
+                        "Object has already been returned to this pool or is invalid");
+            }
+            pooledObject.markReturning(); // Keep from being marked abandoned
+        }
+    }
+
+    /**
+     * Unregisters this pool's MBean.
+     */
+    final void jmxUnregister() {
+        if (objectName != null) {
+            try {
+                ManagementFactory.getPlatformMBeanServer().unregisterMBean(
+                        objectName);
+            } catch (final MBeanRegistrationException | InstanceNotFoundException e) {
+                swallowException(e);
+            }
+        }
+    }
+
+    /**
+     * Registers the pool with the platform MBean server.
+     * The registered name will be
+     * <code>jmxNameBase + jmxNamePrefix + i</code> where i is the least
+     * integer greater than or equal to 1 such that the name is not already
+     * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException
+     * returning null.
+     *
+     * @param config Pool configuration
+     * @param jmxNameBase default base JMX name for this pool
+     * @param jmxNamePrefix name prefix
+     * @return registered ObjectName, null if registration fails
+     */
+    private ObjectName jmxRegister(final BaseObjectPoolConfig<T> config,
+            final String jmxNameBase, String jmxNamePrefix) {
+        ObjectName newObjectName = null;
+        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+        int i = 1;
+        boolean registered = false;
+        String base = config.getJmxNameBase();
+        if (base == null) {
+            base = jmxNameBase;
+        }
+        while (!registered) {
+            try {
+                ObjectName objName;
+                // Skip the numeric suffix for the first pool in case there is
+                // only one so the names are cleaner.
+                if (i == 1) {
+                    objName = new ObjectName(base + jmxNamePrefix);
+                } else {
+                    objName = new ObjectName(base + jmxNamePrefix + i);
+                }
+                mbs.registerMBean(this, objName);
+                newObjectName = objName;
+                registered = true;
+            } catch (final MalformedObjectNameException e) {
+                if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals(
+                        jmxNamePrefix) && jmxNameBase.equals(base)) {
+                    // Shouldn't happen. Skip registration if it does.
+                    registered = true;
+                } else {
+                    // Must be an invalid name. Use the defaults instead.
+                    jmxNamePrefix =
+                            BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX;
+                    base = jmxNameBase;
+                }
+            } catch (final InstanceAlreadyExistsException e) {
+                // Increment the index and try again
+                i++;
+            } catch (final MBeanRegistrationException | NotCompliantMBeanException e) {
+                // Shouldn't happen. Skip registration if it does.
+                registered = true;
+            }
+        }
+        return newObjectName;
+    }
+
+    /**
+     * Gets the stack trace of an exception as a string.
+     * @param e exception to trace
+     * @return exception stack trace as a string
+     */
+    private String getStackTrace(final Exception e) {
+        // Need the exception in string form to prevent the retention of
+        // references to classes in the stack trace that could trigger a memory
+        // leak in a container environment.
+        final Writer w = new StringWriter();
+        final PrintWriter pw = new PrintWriter(w);
+        e.printStackTrace(pw);
+        return w.toString();
+    }
+
+    // Inner classes
+
+    /**
+     * The idle object evictor {@link TimerTask}.
+     *
+     * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
+     */
+    class Evictor implements Runnable {
+
+        private ScheduledFuture<?> scheduledFuture;
+
+        /**
+         * Run pool maintenance.  Evict objects qualifying for eviction and then
+         * ensure that the minimum number of idle instances are available.
+         * Since the Timer that invokes Evictors is shared for all Pools but
+         * pools may exist in different class loaders, the Evictor ensures that
+         * any actions taken are under the class loader of the factory
+         * associated with the pool.
+         */
+        @Override
+        public void run() {
+            final ClassLoader savedClassLoader =
+                    Thread.currentThread().getContextClassLoader();
+            try {
+                if (factoryClassLoader != null) {
+                    // Set the class loader for the factory
+                    final ClassLoader cl = factoryClassLoader.get();
+                    if (cl == null) {
+                        // The pool has been dereferenced and the class loader
+                        // GC'd. Cancel this timer so the pool can be GC'd as
+                        // well.
+                        cancel();
+                        return;
+                    }
+                    Thread.currentThread().setContextClassLoader(cl);
+                }
+
+                // Evict from the pool
+                try {
+                    evict();
+                } catch(final Exception e) {
+                    swallowException(e);
+                } catch(final OutOfMemoryError oome) {
+                    // Log problem but give evictor thread a chance to continue
+                    // in case error is recoverable
+                    oome.printStackTrace(System.err);
+                }
+                // Re-create idle instances.
+                try {
+                    ensureMinIdle();
+                } catch (final Exception e) {
+                    swallowException(e);
+                }
+            } finally {
+                // Restore the previous CCL
+                Thread.currentThread().setContextClassLoader(savedClassLoader);
+            }
+        }
+
+
+        void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) {
+            this.scheduledFuture = scheduledFuture;
+        }
+
+
+        void cancel() {
+            scheduledFuture.cancel(false);
+        }
+    }
+
+    /**
+     * Maintains a cache of values for a single metric and reports
+     * statistics on the cached values.
+     */
+    private class StatsStore {
+
+        private final AtomicLong values[];
+        private final int size;
+        private int index;
+
+        /**
+         * Create a StatsStore with the given cache size.
+         *
+         * @param size number of values to maintain in the cache.
+         */
+        public StatsStore(final int size) {
+            this.size = size;
+            values = new AtomicLong[size];
+            for (int i = 0; i < size; i++) {
+                values[i] = new AtomicLong(-1);
+            }
+        }
+
+        /**
+         * Adds a value to the cache.  If the cache is full, one of the
+         * existing values is replaced by the new value.
+         *
+         * @param value new value to add to the cache.
+         */
+        public synchronized void add(final long value) {
+            values[index].set(value);
+            index++;
+            if (index == size) {
+                index = 0;
+            }
+        }
+
+        /**
+         * Returns the mean of the cached values.
+         *
+         * @return the mean of the cache, truncated to long
+         */
+        public long getMean() {
+            double result = 0;
+            int counter = 0;
+            for (int i = 0; i < size; i++) {
+                final long value = values[i].get();
+                if (value != -1) {
+                    counter++;
+                    result = result * ((counter - 1) / (double) counter) +
+                            value/(double) counter;
+                }
+            }
+            return (long) result;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder builder = new StringBuilder();
+            builder.append("StatsStore [values=");
+            builder.append(Arrays.toString(values));
+            builder.append(", size=");
+            builder.append(size);
+            builder.append(", index=");
+            builder.append(index);
+            builder.append("]");
+            return builder.toString();
+        }
+    }
+
+    /**
+     * The idle object eviction iterator. Holds a reference to the idle objects.
+     */
+    class EvictionIterator implements Iterator<PooledObject<T>> {
+
+        private final Deque<PooledObject<T>> idleObjects;
+        private final Iterator<PooledObject<T>> idleObjectIterator;
+
+        /**
+         * Create an EvictionIterator for the provided idle instance deque.
+         * @param idleObjects underlying deque
+         */
+        EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
+            this.idleObjects = idleObjects;
+
+            if (getLifo()) {
+                idleObjectIterator = idleObjects.descendingIterator();
+            } else {
+                idleObjectIterator = idleObjects.iterator();
+            }
+        }
+
+        /**
+         * Returns the idle object deque referenced by this iterator.
+         * @return the idle object deque
+         */
+        public Deque<PooledObject<T>> getIdleObjects() {
+            return idleObjects;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean hasNext() {
+            return idleObjectIterator.hasNext();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public PooledObject<T> next() {
+            return idleObjectIterator.next();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void remove() {
+            idleObjectIterator.remove();
+        }
+
+    }
+
+    /**
+     * Wrapper for objects under management by the pool.
+     *
+     * GenericObjectPool and GenericKeyedObjectPool maintain references to all
+     * objects under management using maps keyed on the objects. This wrapper
+     * class ensures that objects can work as hash keys.
+     *
+     * @param <T> type of objects in the pool
+     */
+    static class IdentityWrapper<T> {
+        /** Wrapped object */
+        private final T instance;
+
+        /**
+         * Create a wrapper for an instance.
+         *
+         * @param instance object to wrap
+         */
+        public IdentityWrapper(final T instance) {
+            this.instance = instance;
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(instance);
+        }
+
+        @Override
+        @SuppressWarnings("rawtypes")
+        public boolean equals(final Object other) {
+            return  other instanceof IdentityWrapper &&
+                    ((IdentityWrapper) other).instance == instance;
+        }
+
+        /**
+         * @return the wrapped object
+         */
+        public T getObject() {
+            return instance;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder builder = new StringBuilder();
+            builder.append("IdentityWrapper [instance=");
+            builder.append(instance);
+            builder.append("]");
+            return builder.toString();
+        }
+    }
+
+    @Override
+    protected void toStringAppendFields(final StringBuilder builder) {
+        builder.append("maxTotal=");
+        builder.append(maxTotal);
+        builder.append(", blockWhenExhausted=");
+        builder.append(blockWhenExhausted);
+        builder.append(", maxWaitMillis=");
+        builder.append(maxWaitMillis);
+        builder.append(", lifo=");
+        builder.append(lifo);
+        builder.append(", fairness=");
+        builder.append(fairness);
+        builder.append(", testOnCreate=");
+        builder.append(testOnCreate);
+        builder.append(", testOnBorrow=");
+        builder.append(testOnBorrow);
+        builder.append(", testOnReturn=");
+        builder.append(testOnReturn);
+        builder.append(", testWhileIdle=");
+        builder.append(testWhileIdle);
+        builder.append(", timeBetweenEvictionRunsMillis=");
+        builder.append(timeBetweenEvictionRunsMillis);
+        builder.append(", numTestsPerEvictionRun=");
+        builder.append(numTestsPerEvictionRun);
+        builder.append(", minEvictableIdleTimeMillis=");
+        builder.append(minEvictableIdleTimeMillis);
+        builder.append(", softMinEvictableIdleTimeMillis=");
+        builder.append(softMinEvictableIdleTimeMillis);
+        builder.append(", evictionPolicy=");
+        builder.append(evictionPolicy);
+        builder.append(", closeLock=");
+        builder.append(closeLock);
+        builder.append(", closed=");
+        builder.append(closed);
+        builder.append(", evictionLock=");
+        builder.append(evictionLock);
+        builder.append(", evictor=");
+        builder.append(evictor);
+        builder.append(", evictionIterator=");
+        builder.append(evictionIterator);
+        builder.append(", factoryClassLoader=");
+        builder.append(factoryClassLoader);
+        builder.append(", oname=");
+        builder.append(objectName);
+        builder.append(", creationStackTrace=");
+        builder.append(creationStackTrace);
+        builder.append(", borrowedCount=");
+        builder.append(borrowedCount);
+        builder.append(", returnedCount=");
+        builder.append(returnedCount);
+        builder.append(", createdCount=");
+        builder.append(createdCount);
+        builder.append(", destroyedCount=");
+        builder.append(destroyedCount);
+        builder.append(", destroyedByEvictorCount=");
+        builder.append(destroyedByEvictorCount);
+        builder.append(", destroyedByBorrowValidationCount=");
+        builder.append(destroyedByBorrowValidationCount);
+        builder.append(", activeTimes=");
+        builder.append(activeTimes);
+        builder.append(", idleTimes=");
+        builder.append(idleTimes);
+        builder.append(", waitTimes=");
+        builder.append(waitTimes);
+        builder.append(", maxBorrowWaitTimeMillis=");
+        builder.append(maxBorrowWaitTimeMillis);
+        builder.append(", swallowedExceptionListener=");
+        builder.append(swallowedExceptionListener);
+    }
+
+
+}
diff --git a/src/main/java/org/apache/commons/pool2/impl/EvictionTimer.java b/src/main/java/org/apache/commons/pool2/impl/EvictionTimer.java
index 738d53c..86e5b54 100644
--- a/src/main/java/org/apache/commons/pool2/impl/EvictionTimer.java
+++ b/src/main/java/org/apache/commons/pool2/impl/EvictionTimer.java
@@ -1,133 +1,135 @@
-/*
- * 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 java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.TimerTask;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Provides a shared idle object eviction timer for all pools.
- * <p>
- * This class is currently implemented using {@link ScheduledThreadPoolExecutor}. This implementation may change in any
- * future release. This class keeps track of how many pools are using it. If no pools are using the timer, it is
- * cancelled. This prevents a thread being left running which, in application server environments, can lead to memory
- * leads and/or prevent applications from shutting down or reloading cleanly.
- * </p>
- * <p>
- * This class has package scope to prevent its inclusion in the pool public API. The class declaration below should
- * *not* be changed to public.
- * </p>
- * <p>
- * This class is intended to be thread-safe.
- * </p>
- *
- * @since 2.0
- */
-class EvictionTimer {
-
-    /** Executor instance */
-    private static ScheduledThreadPoolExecutor executor; //@GuardedBy("EvictionTimer.class")
-
-    /** Prevent instantiation */
-    private EvictionTimer() {
-        // Hide the default constructor
-    }
-
-
-    /**
-     * @since 2.4.3
-     */
-    @Override
-    public String toString() {
-        final StringBuilder builder = new StringBuilder();
-        builder.append("EvictionTimer []");
-        return builder.toString();
-    }
-
-
-    /**
-     * Add the specified eviction task to the timer. Tasks that are added with a
-     * call to this method *must* call {@link #cancel(TimerTask)} to cancel the
-     * task to prevent memory and/or thread leaks in application server
-     * environments.
-     * 
-     * @param task      Task to be scheduled
-     * @param delay     Delay in milliseconds before task is executed
-     * @param period    Time in milliseconds between executions
-     */
-    static synchronized void schedule(
-            final BaseGenericObjectPool<?>.Evictor task, final long delay, final long period) {
-        if (null == executor) {
-            executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
-            executor.setRemoveOnCancelPolicy(true);
-        }
-        final ScheduledFuture<?> scheduledFuture =
-                executor.scheduleWithFixedDelay(task, delay, period, TimeUnit.MILLISECONDS);
-        task.setScheduledFuture(scheduledFuture);
-    }
-
-    /**
-     * Remove the specified eviction task from the timer.
-     *
-     * @param task      Task to be cancelled
-     * @param timeout   If the associated executor is no longer required, how
-     *                  long should this thread wait for the executor to
-     *                  terminate?
-     * @param unit      The units for the specified timeout
-     */
-    static synchronized void cancel(
-            final BaseGenericObjectPool<?>.Evictor task, final long timeout, final TimeUnit unit) {
-        task.cancel();
-        if (executor != null && executor.getQueue().isEmpty()) {
-            executor.shutdown();
-            try {
-                executor.awaitTermination(timeout, unit);
-            } catch (final InterruptedException e) {
-                // Swallow
-                // Significant API changes would be required to propagate this
-            }
-            executor.setCorePoolSize(0);
-            executor = null;
-        }
-    }
-
-    /**
-     * Thread factory that creates a thread, with the context class loader from this class.
-     */
-    private static class EvictorThreadFactory implements ThreadFactory {
-
-        @Override
-        public Thread newThread(final Runnable runnable) {
-            final Thread thread = new Thread(null, runnable, "commons-pool-evictor-thread");
-
-            AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    thread.setContextClassLoader(EvictorThreadFactory.class.getClassLoader());
-                    return null;
-                }
-            });
-
-            return thread;
-        }
-    }
-}
+/*
+ * 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 java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides a shared idle object eviction timer for all pools.
+ * <p>
+ * This class is currently implemented using {@link ScheduledThreadPoolExecutor}. This implementation may change in any
+ * future release. This class keeps track of how many pools are using it. If no pools are using the timer, it is
+ * cancelled. This prevents a thread being left running which, in application server environments, can lead to memory
+ * leads and/or prevent applications from shutting down or reloading cleanly.
+ * </p>
+ * <p>
+ * This class has package scope to prevent its inclusion in the pool public API. The class declaration below should
+ * *not* be changed to public.
+ * </p>
+ * <p>
+ * This class is intended to be thread-safe.
+ * </p>
+ *
+ * @since 2.0
+ */
+class EvictionTimer {
+
+    /** Executor instance */
+    private static ScheduledThreadPoolExecutor executor; //@GuardedBy("EvictionTimer.class")
+
+    /** Prevent instantiation */
+    private EvictionTimer() {
+        // Hide the default constructor
+    }
+
+
+    /**
+     * @since 2.4.3
+     */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("EvictionTimer []");
+        return builder.toString();
+    }
+
+
+    /**
+     * Add the specified eviction task to the timer. Tasks that are added with a
+     * call to this method *must* call {@link #cancel(TimerTask)} to cancel the
+     * task to prevent memory and/or thread leaks in application server
+     * environments.
+     * 
+     * @param task      Task to be scheduled
+     * @param delay     Delay in milliseconds before task is executed
+     * @param period    Time in milliseconds between executions
+     */
+    static synchronized void schedule(
+            final BaseGenericObjectPool<?>.Evictor task, final long delay, final long period) {
+        if (null == executor) {
+            executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory());
+            executor.setRemoveOnCancelPolicy(true);
+        }
+        final ScheduledFuture<?> scheduledFuture =
+                executor.scheduleWithFixedDelay(task, delay, period, TimeUnit.MILLISECONDS);
+        task.setScheduledFuture(scheduledFuture);
+    }
+
+    /**
+     * Remove the specified eviction task from the timer.
+     *
+     * @param evictor      Task to be cancelled
+     * @param timeout   If the associated executor is no longer required, how
+     *                  long should this thread wait for the executor to
+     *                  terminate?
+     * @param unit      The units for the specified timeout
+     */
+    static synchronized void cancel(
+            final BaseGenericObjectPool<?>.Evictor evictor, final long timeout, final TimeUnit unit) {
+        if (evictor != null) {
+            evictor.cancel();
+        }
+        if (executor != null && executor.getQueue().isEmpty()) {
+            executor.shutdown();
+            try {
+                executor.awaitTermination(timeout, unit);
+            } catch (final InterruptedException e) {
+                // Swallow
+                // Significant API changes would be required to propagate this
+            }
+            executor.setCorePoolSize(0);
+            executor = null;
+        }
+    }
+
+    /**
+     * Thread factory that creates a thread, with the context class loader from this class.
+     */
+    private static class EvictorThreadFactory implements ThreadFactory {
+
+        @Override
+        public Thread newThread(final Runnable runnable) {
+            final Thread thread = new Thread(null, runnable, "commons-pool-evictor-thread");
+
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    thread.setContextClassLoader(EvictorThreadFactory.class.getClassLoader());
+                    return null;
+                }
+            });
+
+            return thread;
+        }
+    }
+}