You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/12/07 17:14:07 UTC

[tomcat] 04/18: Merge in Pool 2 changes to 6092f92 (2019-12-06, 2.8.0-SNAPSHOT)

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

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit a3fd9eee952b99974b23f0b328f5fb3f25f79c5e
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Dec 6 15:43:08 2019 +0000

    Merge in Pool 2 changes to 6092f92 (2019-12-06, 2.8.0-SNAPSHOT)
---
 MERGE.txt                                          |   12 +-
 .../dbcp/pool2/BaseKeyedPooledObjectFactory.java   |    2 +
 .../apache/tomcat/dbcp/pool2/BaseObjectPool.java   |   18 +
 .../apache/tomcat/dbcp/pool2/KeyedObjectPool.java  |  211 ++--
 java/org/apache/tomcat/dbcp/pool2/ObjectPool.java  |  134 ++-
 java/org/apache/tomcat/dbcp/pool2/PoolUtils.java   | 1270 ++------------------
 .../org/apache/tomcat/dbcp/pool2/PooledObject.java |    3 +-
 .../dbcp/pool2/impl/DefaultEvictionPolicy.java     |    2 +
 .../tomcat/dbcp/pool2/impl/EvictionConfig.java     |    1 +
 .../dbcp/pool2/impl/GenericKeyedObjectPool.java    |   78 +-
 .../tomcat/dbcp/pool2/impl/GenericObjectPool.java  |   46 +-
 .../pool2/impl/InterruptibleReentrantLock.java     |    1 +
 .../dbcp/pool2/impl/LinkedBlockingDeque.java       |    4 +
 .../dbcp/pool2/impl/SoftReferenceObjectPool.java   |    3 +
 webapps/docs/changelog.xml                         |    4 +
 15 files changed, 421 insertions(+), 1368 deletions(-)

diff --git a/MERGE.txt b/MERGE.txt
index 893ac89..7daec6d 100644
--- a/MERGE.txt
+++ b/MERGE.txt
@@ -58,15 +58,15 @@ Note: Tomcat's copy of fileupload also includes classes copied manually from
 
 DBCP
 ----
+Pool2
+Sub-tree
+src/main/java/org/apache/commons/pool2
+The SHA1 ID for the most recent commit to be merged to Tomcat is:
+6092f924b36061353ff92b18c88400ab3bc05327 (2019-12-06)
+
 DBCP2
 Sub-tree
 src/main/java/org/apache/commons/dbcp2
 src/main/resources/org/apache/commons/dbcp2
 The SHA1 ID for the most recent commit to be merged to Tomcat is:
 4813b7f5456c1f4fecc4f701ac731a71f57db249 (2019-08-09)
-
-Pool2
-Sub-tree
-src/main/java/org/apache/commons/pool2
-The SHA1 ID for the most recent commit to be merged to Tomcat is:
-796e32d53cc0d870ba0db3a7faf4c5b24ff76f3f (2019-08-01)
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java b/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
index 3dd7429..dfbc5a9 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseKeyedPooledObjectFactory.java
@@ -21,7 +21,9 @@ package org.apache.tomcat.dbcp.pool2;
  * <p>
  * All operations defined here are essentially no-op's.
  * </p>
+ * <p>
  * This class is immutable, and therefore thread-safe.
+ * </p>
  *
  * @see KeyedPooledObjectFactory
  *
diff --git a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
index 29f189a..96d3c00 100644
--- a/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/BaseObjectPool.java
@@ -22,6 +22,7 @@ package org.apache.tomcat.dbcp.pool2;
  * indicating it is unsupported or throw {@link UnsupportedOperationException}.
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @param <T> Type of element pooled in this pool.
  *
@@ -82,6 +83,23 @@ public abstract class BaseObjectPool<T> extends BaseObject implements ObjectPool
     }
 
     /**
+     * Calls {@link ObjectPool#addObject()} <code>count</code>
+     * number of times.
+     *
+     * @param count
+     *            the number of idle objects to add.
+     * @throws Exception
+     *             when {@link ObjectPool#addObject()} fails.
+     * @since 2.8.0
+     */
+    @Override
+    public void addObjects(final int count) throws Exception {
+        for (int i = 0; i < count; i++) {
+            addObject();
+        }
+    }
+
+    /**
      * {@inheritDoc}
      * <p>
      * This affects the behavior of <code>isClosed</code> and
diff --git a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
index 4df37d8..df325ed 100644
--- a/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/KeyedObjectPool.java
@@ -17,6 +17,7 @@
 package org.apache.tomcat.dbcp.pool2;
 
 import java.io.Closeable;
+import java.util.Collection;
 import java.util.NoSuchElementException;
 
 /**
@@ -66,6 +67,60 @@ import java.util.NoSuchElementException;
  * @since 2.0
  */
 public interface KeyedObjectPool<K, V> extends Closeable {
+
+    /**
+     * Create an object using the {@link KeyedPooledObjectFactory factory} or
+     * other implementation dependent mechanism, passivate it, and then place it
+     * in the idle object pool. <code>addObject</code> is useful for
+     * "pre-loading" a pool with idle objects (Optional operation).
+     *
+     * @param key the key a new instance should be added to
+     *
+     * @throws Exception
+     *              when {@link KeyedPooledObjectFactory#makeObject} fails.
+     * @throws IllegalStateException
+     *              after {@link #close} has been called on this pool.
+     * @throws UnsupportedOperationException
+     *              when this pool cannot add new idle objects.
+     */
+    void addObject(K key) throws Exception, IllegalStateException,
+            UnsupportedOperationException;
+
+    /**
+     * Calls {@link KeyedObjectPool#addObject(Object)} with each
+     * key in <code>keys</code> for <code>count</code> number of times. This has
+     * the same effect as calling {@link #addObjects(Object, int)}
+     * for each key in the <code>keys</code> collection.
+     *
+     * @param keys
+     *            {@link Collection} of keys to add objects for.
+     * @param count
+     *            the number of idle objects to add for each <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>keyedPool</code>, <code>keys</code>, or any value
+     *             in <code>keys</code> is <code>null</code>.
+     * @see #addObjects(Object, int)
+     */
+    void addObjects(final Collection<K> keys, final int count) throws Exception, IllegalArgumentException;
+
+    /**
+     * Calls {@link KeyedObjectPool#addObject(Object)}
+     * <code>key</code> <code>count</code> number of times.
+     *
+     * @param key
+     *            the key to add objects for.
+     * @param count
+     *            the number of idle objects to add for <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>key</code> is <code>null</code>.
+     * @since 2.8.0
+     */
+    void addObjects(final K key, final int count) throws Exception, IllegalArgumentException;
+
     /**
      * Obtains an instance from this pool for the specified <code>key</code>.
      * <p>
@@ -105,75 +160,50 @@ public interface KeyedObjectPool<K, V> extends Closeable {
     V borrowObject(K key) throws Exception, NoSuchElementException, IllegalStateException;
 
     /**
-     * Return an instance to the pool. By contract, <code>obj</code>
-     * <strong>must</strong> have been obtained using
-     * {@link #borrowObject borrowObject} or a related method as defined in an
-     * implementation or sub-interface using a <code>key</code> that is
-     * equivalent to the one used to borrow the instance in the first place.
-     *
-     * @param key the key used to obtain the object
-     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     * Clears the pool, removing all pooled instances (optional operation).
      *
-     * @throws IllegalStateException
-     *              if an attempt is made to return an object to the pool that
-     *              is in any state other than allocated (i.e. borrowed).
-     *              Attempting to return an object more than once or attempting
-     *              to return an object that was never borrowed from the pool
-     *              will trigger this exception.
+     * @throws UnsupportedOperationException when this implementation doesn't
+     *                                       support the operation
      *
-     * @throws Exception if an instance cannot be returned to the pool
+     * @throws Exception if the pool cannot be cleared
      */
-    void returnObject(K key, V obj) throws Exception;
+    void clear() throws Exception, UnsupportedOperationException;
 
     /**
-     * Invalidates an object from the pool.
-     * <p>
-     * By contract, <code>obj</code> <strong>must</strong> have been obtained
-     * using {@link #borrowObject borrowObject} or a related method as defined
-     * in an implementation or sub-interface using a <code>key</code> that is
-     * equivalent to the one used to borrow the <code>Object</code> in the first
-     * place.
-     * </p>
-     * <p>
-     * This method should be used when an object that has been borrowed is
-     * determined (due to an exception or other problem) to be invalid.
-     * </p>
+     * Clears the specified pool, removing all pooled instances corresponding to
+     * the given <code>key</code> (optional operation).
      *
-     * @param key the key used to obtain the object
-     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     * @param key the key to clear
      *
-     * @throws Exception if the instance cannot be invalidated
+     * @throws UnsupportedOperationException when this implementation doesn't
+     *                                       support the operation
+     *
+     * @throws Exception if the key cannot be cleared
      */
-    void invalidateObject(K key, V obj) throws Exception;
+    void clear(K key) throws Exception, UnsupportedOperationException;
 
     /**
-     * Create an object using the {@link KeyedPooledObjectFactory factory} or
-     * other implementation dependent mechanism, passivate it, and then place it
-     * in the idle object pool. <code>addObject</code> is useful for
-     * "pre-loading" a pool with idle objects (Optional operation).
-     *
-     * @param key the key a new instance should be added to
-     *
-     * @throws Exception
-     *              when {@link KeyedPooledObjectFactory#makeObject} fails.
-     * @throws IllegalStateException
-     *              after {@link #close} has been called on this pool.
-     * @throws UnsupportedOperationException
-     *              when this pool cannot add new idle objects.
+     * Close this pool, and free any resources associated with it.
+     * <p>
+     * Calling {@link #addObject addObject} or
+     * {@link #borrowObject borrowObject} after invoking this method on a pool
+     * will cause them to throw an {@link IllegalStateException}.
+     * </p>
+     * <p>
+     * Implementations should silently fail if not all resources can be freed.
+     * </p>
      */
-    void addObject(K key) throws Exception, IllegalStateException,
-            UnsupportedOperationException;
+    @Override
+    void close();
 
     /**
-     * Returns the number of instances corresponding to the given
-     * <code>key</code> currently idle in this pool. Returns a negative value if
-     * this information is not available.
-     *
-     * @param key the key to query
-     * @return the number of instances corresponding to the given
-     * <code>key</code> currently idle in this pool.
+     * Returns the total number of instances currently borrowed from this pool but
+     * not yet returned. Returns a negative value if this information is not
+     * available.
+     * @return the total number of instances currently borrowed from this pool but
+     * not yet returned.
      */
-    int getNumIdle(K key);
+    int getNumActive();
 
     /**
      * Returns the number of instances currently borrowed from but not yet
@@ -194,48 +224,55 @@ public interface KeyedObjectPool<K, V> extends Closeable {
     int getNumIdle();
 
     /**
-     * Returns the total number of instances currently borrowed from this pool but
-     * not yet returned. Returns a negative value if this information is not
-     * available.
-     * @return the total number of instances currently borrowed from this pool but
-     * not yet returned.
+     * Returns the number of instances corresponding to the given
+     * <code>key</code> currently idle in this pool. Returns a negative value if
+     * this information is not available.
+     *
+     * @param key the key to query
+     * @return the number of instances corresponding to the given
+     * <code>key</code> currently idle in this pool.
      */
-    int getNumActive();
+    int getNumIdle(K key);
 
     /**
-     * Clears the pool, removing all pooled instances (optional operation).
+     * Invalidates an object from the pool.
+     * <p>
+     * By contract, <code>obj</code> <strong>must</strong> have been obtained
+     * using {@link #borrowObject borrowObject} or a related method as defined
+     * in an implementation or sub-interface using a <code>key</code> that is
+     * equivalent to the one used to borrow the <code>Object</code> in the first
+     * place.
+     * </p>
+     * <p>
+     * This method should be used when an object that has been borrowed is
+     * determined (due to an exception or other problem) to be invalid.
+     * </p>
      *
-     * @throws UnsupportedOperationException when this implementation doesn't
-     *                                       support the operation
+     * @param key the key used to obtain the object
+     * @param obj a {@link #borrowObject borrowed} instance to be returned.
      *
-     * @throws Exception if the pool cannot be cleared
+     * @throws Exception if the instance cannot be invalidated
      */
-    void clear() throws Exception, UnsupportedOperationException;
+    void invalidateObject(K key, V obj) throws Exception;
 
     /**
-     * Clears the specified pool, removing all pooled instances corresponding to
-     * the given <code>key</code> (optional operation).
+     * Return an instance to the pool. By contract, <code>obj</code>
+     * <strong>must</strong> have been obtained using
+     * {@link #borrowObject borrowObject} or a related method as defined in an
+     * implementation or sub-interface using a <code>key</code> that is
+     * equivalent to the one used to borrow the instance in the first place.
      *
-     * @param key the key to clear
+     * @param key the key used to obtain the object
+     * @param obj a {@link #borrowObject borrowed} instance to be returned.
      *
-     * @throws UnsupportedOperationException when this implementation doesn't
-     *                                       support the operation
+     * @throws IllegalStateException
+     *              if an attempt is made to return an object to the pool that
+     *              is in any state other than allocated (i.e. borrowed).
+     *              Attempting to return an object more than once or attempting
+     *              to return an object that was never borrowed from the pool
+     *              will trigger this exception.
      *
-     * @throws Exception if the key cannot be cleared
-     */
-    void clear(K key) throws Exception, UnsupportedOperationException;
-
-    /**
-     * Close this pool, and free any resources associated with it.
-     * <p>
-     * Calling {@link #addObject addObject} or
-     * {@link #borrowObject borrowObject} after invoking this method on a pool
-     * will cause them to throw an {@link IllegalStateException}.
-     * </p>
-     * <p>
-     * Implementations should silently fail if not all resources can be freed.
-     * </p>
+     * @throws Exception if an instance cannot be returned to the pool
      */
-    @Override
-    void close();
+    void returnObject(K key, V obj) throws Exception;
 }
diff --git a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
index 6303245..22eb12a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/ObjectPool.java
@@ -60,6 +60,34 @@ import java.util.NoSuchElementException;
 public interface ObjectPool<T> extends Closeable {
 
     /**
+     * Creates an object using the {@link PooledObjectFactory factory} or other
+     * implementation dependent mechanism, passivate it, and then place it in
+     * the idle object pool. <code>addObject</code> is useful for "pre-loading"
+     * a pool with idle objects. (Optional operation).
+     *
+     * @throws Exception
+     *              when {@link PooledObjectFactory#makeObject} fails.
+     * @throws IllegalStateException
+     *              after {@link #close} has been called on this pool.
+     * @throws UnsupportedOperationException
+     *              when this pool cannot add new idle objects.
+     */
+    void addObject() throws Exception, IllegalStateException,
+            UnsupportedOperationException;
+
+    /**
+     * Calls {@link ObjectPool#addObject()} <code>count</code>
+     * number of times.
+     *
+     * @param count
+     *            the number of idle objects to add.
+     * @throws Exception
+     *             when {@link ObjectPool#addObject()} fails.
+     * @since 2.8.0
+     */
+    void addObjects(final int count) throws Exception;
+
+    /**
      * Obtains an instance from this pool.
      * <p>
      * Instances returned from this method will have been either newly created
@@ -94,56 +122,36 @@ public interface ObjectPool<T> extends Closeable {
             IllegalStateException;
 
     /**
-     * Returns an instance to the pool. By contract, <code>obj</code>
-     * <strong>must</strong> have been obtained using {@link #borrowObject()} or
-     * a related method as defined in an implementation or sub-interface.
-     *
-     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     * Clears any objects sitting idle in the pool, releasing any associated
+     * resources (optional operation). Idle objects cleared must be
+     * {@link PooledObjectFactory#destroyObject(PooledObject)}.
      *
-     * @throws IllegalStateException
-     *              if an attempt is made to return an object to the pool that
-     *              is in any state other than allocated (i.e. borrowed).
-     *              Attempting to return an object more than once or attempting
-     *              to return an object that was never borrowed from the pool
-     *              will trigger this exception.
+     * @throws UnsupportedOperationException
+     *              if this implementation does not support the operation
      *
-     * @throws Exception if an instance cannot be returned to the pool
+     * @throws Exception if the pool cannot be cleared
      */
-    void returnObject(T obj) throws Exception;
+    void clear() throws Exception, UnsupportedOperationException;
 
     /**
-     * Invalidates an object from the pool.
+     * Closes this pool, and free any resources associated with it.
      * <p>
-     * By contract, <code>obj</code> <strong>must</strong> have been obtained
-     * using {@link #borrowObject} or a related method as defined in an
-     * implementation or sub-interface.
+     * Calling {@link #addObject} or {@link #borrowObject} after invoking this
+     * method on a pool will cause them to throw an {@link IllegalStateException}.
      * </p>
      * <p>
-     * This method should be used when an object that has been borrowed is
-     * determined (due to an exception or other problem) to be invalid.
+     * Implementations should silently fail if not all resources can be freed.
      * </p>
-     *
-     * @param obj a {@link #borrowObject borrowed} instance to be disposed.
-     *
-     * @throws Exception if the instance cannot be invalidated
      */
-    void invalidateObject(T obj) throws Exception;
+    @Override
+    void close();
 
     /**
-     * Creates an object using the {@link PooledObjectFactory factory} or other
-     * implementation dependent mechanism, passivate it, and then place it in
-     * the idle object pool. <code>addObject</code> is useful for "pre-loading"
-     * a pool with idle objects. (Optional operation).
-     *
-     * @throws Exception
-     *              when {@link PooledObjectFactory#makeObject} fails.
-     * @throws IllegalStateException
-     *              after {@link #close} has been called on this pool.
-     * @throws UnsupportedOperationException
-     *              when this pool cannot add new idle objects.
+     * Returns the number of instances currently borrowed from this pool. Returns
+     * a negative value if this information is not available.
+     * @return the number of instances currently borrowed from this pool.
      */
-    void addObject() throws Exception, IllegalStateException,
-            UnsupportedOperationException;
+    int getNumActive();
 
     /**
      * Returns the number of instances currently idle in this pool. This may be
@@ -155,34 +163,38 @@ public interface ObjectPool<T> extends Closeable {
     int getNumIdle();
 
     /**
-     * Returns the number of instances currently borrowed from this pool. Returns
-     * a negative value if this information is not available.
-     * @return the number of instances currently borrowed from this pool.
-     */
-    int getNumActive();
-
-    /**
-     * Clears any objects sitting idle in the pool, releasing any associated
-     * resources (optional operation). Idle objects cleared must be
-     * {@link PooledObjectFactory#destroyObject(PooledObject)}.
+     * Invalidates an object from the pool.
+     * <p>
+     * By contract, <code>obj</code> <strong>must</strong> have been obtained
+     * using {@link #borrowObject} or a related method as defined in an
+     * implementation or sub-interface.
+     * </p>
+     * <p>
+     * This method should be used when an object that has been borrowed is
+     * determined (due to an exception or other problem) to be invalid.
+     * </p>
      *
-     * @throws UnsupportedOperationException
-     *              if this implementation does not support the operation
+     * @param obj a {@link #borrowObject borrowed} instance to be disposed.
      *
-     * @throws Exception if the pool cannot be cleared
+     * @throws Exception if the instance cannot be invalidated
      */
-    void clear() throws Exception, UnsupportedOperationException;
+    void invalidateObject(T obj) throws Exception;
 
     /**
-     * Closes this pool, and free any resources associated with it.
-     * <p>
-     * Calling {@link #addObject} or {@link #borrowObject} after invoking this
-     * method on a pool will cause them to throw an {@link IllegalStateException}.
-     * </p>
-     * <p>
-     * Implementations should silently fail if not all resources can be freed.
-     * </p>
+     * Returns an instance to the pool. By contract, <code>obj</code>
+     * <strong>must</strong> have been obtained using {@link #borrowObject()} or
+     * a related method as defined in an implementation or sub-interface.
+     *
+     * @param obj a {@link #borrowObject borrowed} instance to be returned.
+     *
+     * @throws IllegalStateException
+     *              if an attempt is made to return an object to the pool that
+     *              is in any state other than allocated (i.e. borrowed).
+     *              Attempting to return an object more than once or attempting
+     *              to return an object that was never borrowed from the pool
+     *              will trigger this exception.
+     *
+     * @throws Exception if an instance cannot be returned to the pool
      */
-    @Override
-    void close();
+    void returnObject(T obj) throws Exception;
 }
diff --git a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
index 2494351..7df2f9a 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PoolUtils.java
@@ -17,15 +17,12 @@
 package org.apache.tomcat.dbcp.pool2;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
 
 /**
@@ -36,11 +33,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
  */
 public final class PoolUtils {
 
-    private static final String MSG_FACTOR_NEGATIVE = "factor must be positive.";
     private static final String MSG_MIN_IDLE = "minIdle must be non-negative.";
-    private static final String MSG_NULL_KEY = "key must not be null.";
+    public static final String MSG_NULL_KEY = "key must not be null.";
     private static final String MSG_NULL_KEYED_POOL = "keyedPool must not be null.";
-    private static final String MSG_NULL_KEYS = "keys must not be null.";
+    public static final String MSG_NULL_KEYS = "keys must not be null.";
     private static final String MSG_NULL_POOL = "pool must not be null.";
 
     /**
@@ -220,15 +216,15 @@ public final class PoolUtils {
      *             when {@link ObjectPool#addObject()} fails.
      * @throws IllegalArgumentException
      *             when <code>pool</code> is <code>null</code>.
+     * @deprecated Use {@link ObjectPool#addObjects(int)}.
      */
+    @Deprecated
     public static <T> void prefill(final ObjectPool<T> pool, final int count)
             throws Exception, IllegalArgumentException {
         if (pool == null) {
             throw new IllegalArgumentException(MSG_NULL_POOL);
         }
-        for (int i = 0; i < count; i++) {
-            pool.addObject();
-        }
+        pool.addObjects(count);
     }
 
     /**
@@ -248,19 +244,16 @@ public final class PoolUtils {
      * @throws IllegalArgumentException
      *             when <code>keyedPool</code> or <code>key</code> is
      *             <code>null</code>.
+     * @deprecated Use {@link KeyedObjectPool#addObjects(Object, int)}.
      */
+    @Deprecated
     public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
             final K key, final int count) throws Exception,
             IllegalArgumentException {
         if (keyedPool == null) {
             throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
         }
-        if (key == null) {
-            throw new IllegalArgumentException(MSG_NULL_KEY);
-        }
-        for (int i = 0; i < count; i++) {
-            keyedPool.addObject(key);
-        }
+        keyedPool.addObjects(key, count);
     }
 
     /**
@@ -283,85 +276,16 @@ public final class PoolUtils {
      *             when <code>keyedPool</code>, <code>keys</code>, or any value
      *             in <code>keys</code> is <code>null</code>.
      * @see #prefill(KeyedObjectPool, Object, int)
+     * @deprecated Use {@link KeyedObjectPool#addObjects(Collection, int)}.
      */
+    @Deprecated
     public static <K, V> void prefill(final KeyedObjectPool<K, V> keyedPool,
             final Collection<K> keys, final int count) throws Exception,
             IllegalArgumentException {
         if (keys == null) {
             throw new IllegalArgumentException(MSG_NULL_KEYS);
         }
-        final Iterator<K> iter = keys.iterator();
-        while (iter.hasNext()) {
-            prefill(keyedPool, iter.next(), count);
-        }
-    }
-
-    /**
-     * Returns a synchronized (thread-safe) ObjectPool backed by the specified
-     * ObjectPool.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
-     * </p>
-     *
-     * @param pool
-     *            the ObjectPool to be "wrapped" in a synchronized ObjectPool.
-     * @param <T> the type of objects in the pool
-     * @return a synchronized view of the specified ObjectPool.
-     */
-    public static <T> ObjectPool<T> synchronizedPool(final ObjectPool<T> pool) {
-        if (pool == null) {
-            throw new IllegalArgumentException(MSG_NULL_POOL);
-        }
-        /*
-         * assert !(pool instanceof GenericObjectPool) :
-         * "GenericObjectPool is already thread-safe"; assert !(pool instanceof
-         * SoftReferenceObjectPool) :
-         * "SoftReferenceObjectPool is already thread-safe"; assert !(pool
-         * instanceof StackObjectPool) :
-         * "StackObjectPool is already thread-safe"; assert
-         * !"org.apache.commons.pool.composite.CompositeObjectPool"
-         * .equals(pool.getClass().getName()) :
-         * "CompositeObjectPools are already thread-safe";
-         */
-        return new SynchronizedObjectPool<>(pool);
-    }
-
-    /**
-     * Returns a synchronized (thread-safe) KeyedObjectPool backed by the
-     * specified KeyedObjectPool.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
-     * </p>
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be "wrapped" in a synchronized
-     *            KeyedObjectPool.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a synchronized view of the specified KeyedObjectPool.
-     */
-    public static <K, V> KeyedObjectPool<K, V> synchronizedPool(
-            final KeyedObjectPool<K, V> keyedPool) {
-        /*
-         * assert !(keyedPool instanceof GenericKeyedObjectPool) :
-         * "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool
-         * instanceof StackKeyedObjectPool) :
-         * "StackKeyedObjectPool is already thread-safe"; assert
-         * !"org.apache.commons.pool.composite.CompositeKeyedObjectPool"
-         * .equals(keyedPool.getClass().getName()) :
-         * "CompositeKeyedObjectPools are already thread-safe";
-         */
-        return new SynchronizedKeyedObjectPool<>(keyedPool);
+        keyedPool.addObjects(keys, count);
     }
 
     /**
@@ -396,167 +320,6 @@ public final class PoolUtils {
     }
 
     /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     *
-     * @param pool
-     *            the ObjectPool to be decorated so it shrinks its idle count
-     *            when possible.
-     * @param <T> the type of objects in the pool
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(ObjectPool, float)
-     */
-    public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool) {
-        return erodingPool(pool, 1f);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     * <p>
-     * The factor parameter provides a mechanism to tweak the rate at which the
-     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
-     * try to shrink its size more often. Values greater than 1 cause the pool
-     * to less frequently try to shrink its size.
-     * </p>
-     *
-     * @param pool
-     *            the ObjectPool to be decorated so it shrinks its idle count
-     *            when possible.
-     * @param factor
-     *            a positive value to scale the rate at which the pool tries to
-     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
-     *            shrinks more aggressively. If 1 &lt; factor then the pool
-     *            shrinks less aggressively.
-     * @param <T> the type of objects in the pool
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(ObjectPool)
-     */
-    public static <T> ObjectPool<T> erodingPool(final ObjectPool<T> pool,
-            final float factor) {
-        if (pool == null) {
-            throw new IllegalArgumentException(MSG_NULL_POOL);
-        }
-        if (factor <= 0f) {
-            throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
-        }
-        return new ErodingObjectPool<>(pool, factor);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be decorated so it shrinks its idle
-     *            count when possible.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(KeyedObjectPool, float)
-     * @see #erodingPool(KeyedObjectPool, float, boolean)
-     */
-    public static <K, V> KeyedObjectPool<K, V> erodingPool(
-            final KeyedObjectPool<K, V> keyedPool) {
-        return erodingPool(keyedPool, 1f);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     * <p>
-     * The factor parameter provides a mechanism to tweak the rate at which the
-     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
-     * try to shrink its size more often. Values greater than 1 cause the pool
-     * to less frequently try to shrink its size.
-     * </p>
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be decorated so it shrinks its idle
-     *            count when possible.
-     * @param factor
-     *            a positive value to scale the rate at which the pool tries to
-     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
-     *            shrinks more aggressively. If 1 &lt; factor then the pool
-     *            shrinks less aggressively.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(KeyedObjectPool, float, boolean)
-     */
-    public static <K, V> KeyedObjectPool<K, V> erodingPool(
-            final KeyedObjectPool<K, V> keyedPool, final float factor) {
-        return erodingPool(keyedPool, factor, false);
-    }
-
-    /**
-     * Returns a pool that adaptively decreases its size when idle objects are
-     * no longer needed. This is intended as an always thread-safe alternative
-     * to using an idle object evictor provided by many pool implementations.
-     * This is also an effective way to shrink FIFO ordered pools that
-     * experience load spikes.
-     * <p>
-     * The factor parameter provides a mechanism to tweak the rate at which the
-     * pool tries to shrink its size. Values between 0 and 1 cause the pool to
-     * try to shrink its size more often. Values greater than 1 cause the pool
-     * to less frequently try to shrink its size.
-     * </p>
-     * <p>
-     * The perKey parameter determines if the pool shrinks on a whole pool basis
-     * or a per key basis. When perKey is false, the keys do not have an effect
-     * on the rate at which the pool tries to shrink its size. When perKey is
-     * true, each key is shrunk independently.
-     * </p>
-     *
-     * @param keyedPool
-     *            the KeyedObjectPool to be decorated so it shrinks its idle
-     *            count when possible.
-     * @param factor
-     *            a positive value to scale the rate at which the pool tries to
-     *            reduce its size. If 0 &lt; factor &lt; 1 then the pool
-     *            shrinks more aggressively. If 1 &lt; factor then the pool
-     *            shrinks less aggressively.
-     * @param perKey
-     *            when true, each key is treated independently.
-     * @param <K> the type of the pool key
-     * @param <V> the type of pool entries
-     * @return a pool that adaptively decreases its size when idle objects are
-     *         no longer needed.
-     * @see #erodingPool(KeyedObjectPool)
-     * @see #erodingPool(KeyedObjectPool, float)
-     */
-    public static <K, V> KeyedObjectPool<K, V> erodingPool(
-            final KeyedObjectPool<K, V> keyedPool, final float factor,
-            final boolean perKey) {
-        if (keyedPool == null) {
-            throw new IllegalArgumentException(MSG_NULL_KEYED_POOL);
-        }
-        if (factor <= 0f) {
-            throw new IllegalArgumentException(MSG_FACTOR_NEGATIVE);
-        }
-        if (perKey) {
-            return new ErodingPerKeyKeyedObjectPool<>(keyedPool, factor);
-        }
-        return new ErodingKeyedObjectPool<>(keyedPool, factor);
-    }
-
-    /**
      * Gets the <code>Timer</code> for checking keyedPool's idle count.
      *
      * @return the {@link Timer} for checking keyedPool's idle count.
@@ -718,73 +481,51 @@ public final class PoolUtils {
     }
 
     /**
-     * A synchronized (thread-safe) ObjectPool backed by the specified
-     * ObjectPool.
+     * A fully synchronized PooledObjectFactory that wraps a
+     * PooledObjectFactory and synchronizes access to the wrapped factory
+     * methods.
      * <p>
      * <b>Note:</b> This should not be used on pool implementations that already
      * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
+     * Pool library.
      * </p>
      *
-     * @param <T> type of objects in the pool
+     * @param <T> pooled object factory type
      */
-    private static final class SynchronizedObjectPool<T> implements ObjectPool<T> {
+    private static final class SynchronizedPooledObjectFactory<T> implements
+            PooledObjectFactory<T> {
 
-        /**
-         * Object whose monitor is used to synchronize methods on the wrapped
-         * pool.
-         */
-        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+        /** Synchronization lock */
+        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
 
-        /** the underlying object pool */
-        private final ObjectPool<T> pool;
+        /** Wrapped factory */
+        private final PooledObjectFactory<T> factory;
 
         /**
-         * Creates a new SynchronizedObjectPool wrapping the given pool.
+         * Creates a SynchronizedPoolableObjectFactory wrapping the given
+         * factory.
          *
-         * @param pool
-         *            the ObjectPool to be "wrapped" in a synchronized
-         *            ObjectPool.
+         * @param factory
+         *            underlying factory to wrap
          * @throws IllegalArgumentException
-         *             if the pool is null
+         *             if the factory is null
          */
-        SynchronizedObjectPool(final ObjectPool<T> pool)
+        SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
                 throws IllegalArgumentException {
-            if (pool == null) {
-                throw new IllegalArgumentException(MSG_NULL_POOL);
-            }
-            this.pool = pool;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public T borrowObject() throws Exception, NoSuchElementException,
-                IllegalStateException {
-            final WriteLock writeLock = readWriteLock.writeLock();
-            writeLock.lock();
-            try {
-                return pool.borrowObject();
-            } finally {
-                writeLock.unlock();
+            if (factory == null) {
+                throw new IllegalArgumentException("factory must not be null.");
             }
+            this.factory = factory;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public void returnObject(final T obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public PooledObject<T> makeObject() throws Exception {
             writeLock.lock();
             try {
-                pool.returnObject(obj);
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                return factory.makeObject();
             } finally {
                 writeLock.unlock();
             }
@@ -794,13 +535,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void invalidateObject(final T obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void destroyObject(final PooledObject<T> p) throws Exception {
             writeLock.lock();
             try {
-                pool.invalidateObject(obj);
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                factory.destroyObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -810,12 +548,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void addObject() throws Exception, IllegalStateException,
-                UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public boolean validateObject(final PooledObject<T> p) {
             writeLock.lock();
             try {
-                pool.addObject();
+                return factory.validateObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -825,39 +561,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public int getNumIdle() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return pool.getNumIdle();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return pool.getNumActive();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void activateObject(final PooledObject<T> p) throws Exception {
             writeLock.lock();
             try {
-                pool.clear();
+                factory.activateObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -867,13 +574,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void close() {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void passivateObject(final PooledObject<T> p) throws Exception {
             writeLock.lock();
             try {
-                pool.close();
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                factory.passivateObject(p);
             } finally {
                 writeLock.unlock();
             }
@@ -885,83 +589,62 @@ public final class PoolUtils {
         @Override
         public String toString() {
             final StringBuilder sb = new StringBuilder();
-            sb.append("SynchronizedObjectPool");
-            sb.append("{pool=").append(pool);
+            sb.append("SynchronizedPoolableObjectFactory");
+            sb.append("{factory=").append(factory);
             sb.append('}');
             return sb.toString();
         }
     }
 
     /**
-     * A synchronized (thread-safe) KeyedObjectPool backed by the specified
-     * KeyedObjectPool.
+     * A fully synchronized KeyedPooledObjectFactory that wraps a
+     * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
+     * methods.
      * <p>
      * <b>Note:</b> This should not be used on pool implementations that already
      * provide proper synchronization such as the pools provided in the Commons
-     * Pool library. Wrapping a pool that {@link #wait() waits} for poolable
-     * objects to be returned before allowing another one to be borrowed with
-     * another layer of synchronization will cause liveliness issues or a
-     * deadlock.
+     * Pool library.
      * </p>
      *
-     * @param <K> object pool key type
-     * @param <V> object pool value type
+     * @param <K> pooled object factory key type
+     * @param <V> pooled object factory key value
      */
-    private static final class SynchronizedKeyedObjectPool<K, V> implements
-            KeyedObjectPool<K, V> {
+    private static final class SynchronizedKeyedPooledObjectFactory<K, V>
+            implements KeyedPooledObjectFactory<K, V> {
 
-        /**
-         * Object whose monitor is used to synchronize methods on the wrapped
-         * pool.
-         */
-        private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+        /** Synchronization lock */
+        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
 
-        /** Underlying object pool */
-        private final KeyedObjectPool<K, V> keyedPool;
+        /** Wrapped factory */
+        private final KeyedPooledObjectFactory<K, V> keyedFactory;
 
         /**
-         * Creates a new SynchronizedKeyedObjectPool wrapping the given pool
+         * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
+         * factory.
          *
-         * @param keyedPool
-         *            KeyedObjectPool to wrap
+         * @param keyedFactory
+         *            underlying factory to wrap
          * @throws IllegalArgumentException
-         *             if keyedPool is null
+         *             if the factory is null
          */
-        SynchronizedKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool)
+        SynchronizedKeyedPooledObjectFactory(
+                final KeyedPooledObjectFactory<K, V> keyedFactory)
                 throws IllegalArgumentException {
-            if (keyedPool == null) {
+            if (keyedFactory == null) {
                 throw new IllegalArgumentException(
-                        MSG_NULL_KEYED_POOL);
-            }
-            this.keyedPool = keyedPool;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public V borrowObject(final K key) throws Exception,
-                NoSuchElementException, IllegalStateException {
-            final WriteLock writeLock = readWriteLock.writeLock();
-            writeLock.lock();
-            try {
-                return keyedPool.borrowObject(key);
-            } finally {
-                writeLock.unlock();
+                        "keyedFactory must not be null.");
             }
+            this.keyedFactory = keyedFactory;
         }
 
         /**
          * {@inheritDoc}
          */
         @Override
-        public void returnObject(final K key, final V obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public PooledObject<V> makeObject(final K key) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.returnObject(key, obj);
-            } catch (final Exception e) {
-                // swallowed
+                return keyedFactory.makeObject(key);
             } finally {
                 writeLock.unlock();
             }
@@ -971,13 +654,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void invalidateObject(final K key, final V obj) {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.invalidateObject(key, obj);
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
+                keyedFactory.destroyObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -987,12 +667,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void addObject(final K key) throws Exception,
-                IllegalStateException, UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public boolean validateObject(final K key, final PooledObject<V> p) {
             writeLock.lock();
             try {
-                keyedPool.addObject(key);
+                return keyedFactory.validateObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -1002,67 +680,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public int getNumIdle(final K key) {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumIdle(key);
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive(final K key) {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumActive(key);
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumIdle();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            final ReadLock readLock = readWriteLock.readLock();
-            readLock.lock();
-            try {
-                return keyedPool.getNumActive();
-            } finally {
-                readLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void activateObject(final K key, final PooledObject<V> p) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.clear();
+                keyedFactory.activateObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -1072,263 +693,10 @@ public final class PoolUtils {
          * {@inheritDoc}
          */
         @Override
-        public void clear(final K key) throws Exception,
-                UnsupportedOperationException {
-            final WriteLock writeLock = readWriteLock.writeLock();
+        public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
             writeLock.lock();
             try {
-                keyedPool.clear(key);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void close() {
-            final WriteLock writeLock = readWriteLock.writeLock();
-            writeLock.lock();
-            try {
-                keyedPool.close();
-            } catch (final Exception e) {
-                // swallowed as of Pool 2
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("SynchronizedKeyedObjectPool");
-            sb.append("{keyedPool=").append(keyedPool);
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-    /**
-     * A fully synchronized PooledObjectFactory that wraps a
-     * PooledObjectFactory and synchronizes access to the wrapped factory
-     * methods.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library.
-     * </p>
-     *
-     * @param <T> pooled object factory type
-     */
-    private static final class SynchronizedPooledObjectFactory<T> implements
-            PooledObjectFactory<T> {
-
-        /** Synchronization lock */
-        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
-
-        /** Wrapped factory */
-        private final PooledObjectFactory<T> factory;
-
-        /**
-         * Creates a SynchronizedPoolableObjectFactory wrapping the given
-         * factory.
-         *
-         * @param factory
-         *            underlying factory to wrap
-         * @throws IllegalArgumentException
-         *             if the factory is null
-         */
-        SynchronizedPooledObjectFactory(final PooledObjectFactory<T> factory)
-                throws IllegalArgumentException {
-            if (factory == null) {
-                throw new IllegalArgumentException("factory must not be null.");
-            }
-            this.factory = factory;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public PooledObject<T> makeObject() throws Exception {
-            writeLock.lock();
-            try {
-                return factory.makeObject();
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void destroyObject(final PooledObject<T> p) throws Exception {
-            writeLock.lock();
-            try {
-                factory.destroyObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean validateObject(final PooledObject<T> p) {
-            writeLock.lock();
-            try {
-                return factory.validateObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void activateObject(final PooledObject<T> p) throws Exception {
-            writeLock.lock();
-            try {
-                factory.activateObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void passivateObject(final PooledObject<T> p) throws Exception {
-            writeLock.lock();
-            try {
-                factory.passivateObject(p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            sb.append("SynchronizedPoolableObjectFactory");
-            sb.append("{factory=").append(factory);
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-    /**
-     * A fully synchronized KeyedPooledObjectFactory that wraps a
-     * KeyedPooledObjectFactory and synchronizes access to the wrapped factory
-     * methods.
-     * <p>
-     * <b>Note:</b> This should not be used on pool implementations that already
-     * provide proper synchronization such as the pools provided in the Commons
-     * Pool library.
-     * </p>
-     *
-     * @param <K> pooled object factory key type
-     * @param <V> pooled object factory key value
-     */
-    private static final class SynchronizedKeyedPooledObjectFactory<K, V>
-            implements KeyedPooledObjectFactory<K, V> {
-
-        /** Synchronization lock */
-        private final WriteLock writeLock = new ReentrantReadWriteLock().writeLock();
-
-        /** Wrapped factory */
-        private final KeyedPooledObjectFactory<K, V> keyedFactory;
-
-        /**
-         * Creates a SynchronizedKeyedPoolableObjectFactory wrapping the given
-         * factory.
-         *
-         * @param keyedFactory
-         *            underlying factory to wrap
-         * @throws IllegalArgumentException
-         *             if the factory is null
-         */
-        SynchronizedKeyedPooledObjectFactory(
-                final KeyedPooledObjectFactory<K, V> keyedFactory)
-                throws IllegalArgumentException {
-            if (keyedFactory == null) {
-                throw new IllegalArgumentException(
-                        "keyedFactory must not be null.");
-            }
-            this.keyedFactory = keyedFactory;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public PooledObject<V> makeObject(final K key) throws Exception {
-            writeLock.lock();
-            try {
-                return keyedFactory.makeObject(key);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void destroyObject(final K key, final PooledObject<V> p) throws Exception {
-            writeLock.lock();
-            try {
-                keyedFactory.destroyObject(key, p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public boolean validateObject(final K key, final PooledObject<V> p) {
-            writeLock.lock();
-            try {
-                return keyedFactory.validateObject(key, p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void activateObject(final K key, final PooledObject<V> p) throws Exception {
-            writeLock.lock();
-            try {
-                keyedFactory.activateObject(key, p);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void passivateObject(final K key, final PooledObject<V> p) throws Exception {
-            writeLock.lock();
-            try {
-                keyedFactory.passivateObject(key, p);
+                keyedFactory.passivateObject(key, p);
             } finally {
                 writeLock.unlock();
             }
@@ -1346,492 +714,4 @@ public final class PoolUtils {
             return sb.toString();
         }
     }
-
-    /**
-     * Encapsulate the logic for when the next poolable object should be
-     * discarded. Each time update is called, the next time to shrink is
-     * recomputed, based on the float factor, number of idle instances in the
-     * pool and high water mark. Float factor is assumed to be between 0 and 1.
-     * Values closer to 1 cause less frequent erosion events. Erosion event
-     * timing also depends on numIdle. When this value is relatively high (close
-     * to previously established high water mark), erosion occurs more
-     * frequently.
-     */
-    private static final class ErodingFactor {
-        /** Determines frequency of "erosion" events */
-        private final float factor;
-
-        /** Time of next shrink event */
-        private transient volatile long nextShrink;
-
-        /** High water mark - largest numIdle encountered */
-        private transient volatile int idleHighWaterMark;
-
-        /**
-         * Creates a new ErodingFactor with the given erosion factor.
-         *
-         * @param factor
-         *            erosion factor
-         */
-        public ErodingFactor(final float factor) {
-            this.factor = factor;
-            nextShrink = System.currentTimeMillis() + (long) (900000 * factor); // now
-                                                                                // +
-                                                                                // 15
-                                                                                // min
-                                                                                // *
-                                                                                // factor
-            idleHighWaterMark = 1;
-        }
-
-        /**
-         * Updates internal state using the supplied time and numIdle.
-         *
-         * @param now
-         *            current time
-         * @param numIdle
-         *            number of idle elements in the pool
-         */
-        public void update(final long now, final int numIdle) {
-            final int idle = Math.max(0, numIdle);
-            idleHighWaterMark = Math.max(idle, idleHighWaterMark);
-            final float maxInterval = 15f;
-            final float minutes = maxInterval +
-                    ((1f - maxInterval) / idleHighWaterMark) * idle;
-            nextShrink = now + (long) (minutes * 60000f * factor);
-        }
-
-        /**
-         * Returns the time of the next erosion event.
-         *
-         * @return next shrink time
-         */
-        public long getNextShrink() {
-            return nextShrink;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingFactor{" + "factor=" + factor +
-                    ", idleHighWaterMark=" + idleHighWaterMark + '}';
-        }
-    }
-
-    /**
-     * Decorates an object pool, adding "eroding" behavior. Based on the
-     * configured {@link #factor erosion factor}, objects returning to the pool
-     * may be invalidated instead of being added to idle capacity.
-     *
-     * @param <T> type of objects in the pool
-     */
-    private static class ErodingObjectPool<T> implements ObjectPool<T> {
-
-        /** Underlying object pool */
-        private final ObjectPool<T> pool;
-
-        /** Erosion factor */
-        private final ErodingFactor factor;
-
-        /**
-         * Creates an ErodingObjectPool wrapping the given pool using the
-         * specified erosion factor.
-         *
-         * @param pool
-         *            underlying pool
-         * @param factor
-         *            erosion factor - determines the frequency of erosion
-         *            events
-         * @see #factor
-         */
-        public ErodingObjectPool(final ObjectPool<T> pool, final float factor) {
-            this.pool = pool;
-            this.factor = new ErodingFactor(factor);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public T borrowObject() throws Exception, NoSuchElementException,
-                IllegalStateException {
-            return pool.borrowObject();
-        }
-
-        /**
-         * Returns obj to the pool, unless erosion is triggered, in which case
-         * obj is invalidated. Erosion is triggered when there are idle
-         * instances in the pool and more than the {@link #factor erosion
-         * factor}-determined time has elapsed since the last returnObject
-         * activation.
-         *
-         * @param obj
-         *            object to return or invalidate
-         * @see #factor
-         */
-        @Override
-        public void returnObject(final T obj) {
-            boolean discard = false;
-            final long now = System.currentTimeMillis();
-            synchronized (pool) {
-                if (factor.getNextShrink() < now) { // XXX: Pool 3: move test
-                                                    // out of sync block
-                    final int numIdle = pool.getNumIdle();
-                    if (numIdle > 0) {
-                        discard = true;
-                    }
-
-                    factor.update(now, numIdle);
-                }
-            }
-            try {
-                if (discard) {
-                    pool.invalidateObject(obj);
-                } else {
-                    pool.returnObject(obj);
-                }
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void invalidateObject(final T obj) {
-            try {
-                pool.invalidateObject(obj);
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void addObject() throws Exception, IllegalStateException,
-                UnsupportedOperationException {
-            pool.addObject();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle() {
-            return pool.getNumIdle();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            return pool.getNumActive();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            pool.clear();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void close() {
-            try {
-                pool.close();
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingObjectPool{" + "factor=" + factor + ", pool=" +
-                    pool + '}';
-        }
-    }
-
-    /**
-     * Decorates a keyed object pool, adding "eroding" behavior. Based on the
-     * configured erosion factor, objects returning to the pool
-     * may be invalidated instead of being added to idle capacity.
-     *
-     * @param <K> object pool key type
-     * @param <V> object pool value type
-     */
-    private static class ErodingKeyedObjectPool<K, V> implements
-            KeyedObjectPool<K, V> {
-
-        /** Underlying pool */
-        private final KeyedObjectPool<K, V> keyedPool;
-
-        /** Erosion factor */
-        private final ErodingFactor erodingFactor;
-
-        /**
-         * Creates an ErodingObjectPool wrapping the given pool using the
-         * specified erosion factor.
-         *
-         * @param keyedPool
-         *            underlying pool
-         * @param factor
-         *            erosion factor - determines the frequency of erosion
-         *            events
-         * @see #erodingFactor
-         */
-        public ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
-                final float factor) {
-            this(keyedPool, new ErodingFactor(factor));
-        }
-
-        /**
-         * Creates an ErodingObjectPool wrapping the given pool using the
-         * specified erosion factor.
-         *
-         * @param keyedPool
-         *            underlying pool - must not be null
-         * @param erodingFactor
-         *            erosion factor - determines the frequency of erosion
-         *            events
-         * @see #erodingFactor
-         */
-        protected ErodingKeyedObjectPool(final KeyedObjectPool<K, V> keyedPool,
-                final ErodingFactor erodingFactor) {
-            if (keyedPool == null) {
-                throw new IllegalArgumentException(
-                        MSG_NULL_KEYED_POOL);
-            }
-            this.keyedPool = keyedPool;
-            this.erodingFactor = erodingFactor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public V borrowObject(final K key) throws Exception,
-                NoSuchElementException, IllegalStateException {
-            return keyedPool.borrowObject(key);
-        }
-
-        /**
-         * Returns obj to the pool, unless erosion is triggered, in which case
-         * obj is invalidated. Erosion is triggered when there are idle
-         * instances in the pool associated with the given key and more than the
-         * configured {@link #erodingFactor erosion factor} time has elapsed
-         * since the last returnObject activation.
-         *
-         * @param obj
-         *            object to return or invalidate
-         * @param key
-         *            key
-         * @see #erodingFactor
-         */
-        @Override
-        public void returnObject(final K key, final V obj) throws Exception {
-            boolean discard = false;
-            final long now = System.currentTimeMillis();
-            final ErodingFactor factor = getErodingFactor(key);
-            synchronized (keyedPool) {
-                if (factor.getNextShrink() < now) {
-                    final int numIdle = getNumIdle(key);
-                    if (numIdle > 0) {
-                        discard = true;
-                    }
-
-                    factor.update(now, numIdle);
-                }
-            }
-            try {
-                if (discard) {
-                    keyedPool.invalidateObject(key, obj);
-                } else {
-                    keyedPool.returnObject(key, obj);
-                }
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * Returns the eroding factor for the given key
-         *
-         * @param key
-         *            key
-         * @return eroding factor for the given keyed pool
-         */
-        protected ErodingFactor getErodingFactor(final K key) {
-            return erodingFactor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void invalidateObject(final K key, final V obj) {
-            try {
-                keyedPool.invalidateObject(key, obj);
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void addObject(final K key) throws Exception,
-                IllegalStateException, UnsupportedOperationException {
-            keyedPool.addObject(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle() {
-            return keyedPool.getNumIdle();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumIdle(final K key) {
-            return keyedPool.getNumIdle(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive() {
-            return keyedPool.getNumActive();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public int getNumActive(final K key) {
-            return keyedPool.getNumActive(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear() throws Exception, UnsupportedOperationException {
-            keyedPool.clear();
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void clear(final K key) throws Exception,
-                UnsupportedOperationException {
-            keyedPool.clear(key);
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public void close() {
-            try {
-                keyedPool.close();
-            } catch (final Exception e) {
-                // swallowed
-            }
-        }
-
-        /**
-         * Returns the underlying pool
-         *
-         * @return the keyed pool that this ErodingKeyedObjectPool wraps
-         */
-        protected KeyedObjectPool<K, V> getKeyedPool() {
-            return keyedPool;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingKeyedObjectPool{" + "factor=" +
-                    erodingFactor + ", keyedPool=" + keyedPool + '}';
-        }
-    }
-
-    /**
-     * Extends ErodingKeyedObjectPool to allow erosion to take place on a
-     * per-key basis. Timing of erosion events is tracked separately for
-     * separate keyed pools.
-     *
-     * @param <K> object pool key type
-     * @param <V> object pool value type
-     */
-    private static final class ErodingPerKeyKeyedObjectPool<K, V> extends
-            ErodingKeyedObjectPool<K, V> {
-
-        /** Erosion factor - same for all pools */
-        private final float factor;
-
-        /** Map of ErodingFactor instances keyed on pool keys */
-        private final Map<K, ErodingFactor> factors = Collections.synchronizedMap(new HashMap<K, ErodingFactor>());
-
-        /**
-         * Creates a new ErordingPerKeyKeyedObjectPool decorating the given keyed
-         * pool with the specified erosion factor.
-         *
-         * @param keyedPool
-         *            underlying keyed pool
-         * @param factor
-         *            erosion factor
-         */
-        public ErodingPerKeyKeyedObjectPool(
-                final KeyedObjectPool<K, V> keyedPool, final float factor) {
-            super(keyedPool, null);
-            this.factor = factor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        protected ErodingFactor getErodingFactor(final K key) {
-            ErodingFactor eFactor = factors.get(key);
-            // this may result in two ErodingFactors being created for a key
-            // since they are small and cheap this is okay.
-            if (eFactor == null) {
-                eFactor = new ErodingFactor(this.factor);
-                factors.put(key, eFactor);
-            }
-            return eFactor;
-        }
-
-        /**
-         * {@inheritDoc}
-         */
-        @Override
-        public String toString() {
-            return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +
-                    ", keyedPool=" + getKeyedPool() + '}';
-        }
-    }
 }
diff --git a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
index 361b3d8..1bfb803 100644
--- a/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
+++ b/java/org/apache/tomcat/dbcp/pool2/PooledObject.java
@@ -24,6 +24,7 @@ import java.util.Deque;
  * state, for the pooled objects.
  * <p>
  * Implementations of this class are required to be thread-safe.
+ * </p>
  *
  * @param <T> the type of object in the pool
  *
@@ -185,7 +186,7 @@ public interface PooledObject<T> extends Comparable<PooledObject<T>> {
      * @param requireFullStackTrace the new configuration setting for abandoned object logging
      * @since 2.7.0
      */
-    void setRequireFullStackTrace(boolean requireFullStackTrace);
+    void setRequireFullStackTrace(final boolean requireFullStackTrace);
 
     /**
      * Record the current stack trace as the last time the object was used.
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
index fdacc6e..fc618a5 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/DefaultEvictionPolicy.java
@@ -31,7 +31,9 @@ import org.apache.tomcat.dbcp.pool2.PooledObject;
  *     {@link GenericObjectPool#getSoftMinEvictableIdleTimeMillis()} /
  *     {@link GenericKeyedObjectPool#getSoftMinEvictableIdleTimeMillis()}
  * </ul>
+ * <p>
  * This class is immutable and thread-safe.
+ * </p>
  *
  * @param <T> the type of objects in the pool
  *
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
index 49766f0..b124676 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/EvictionConfig.java
@@ -22,6 +22,7 @@ package org.apache.tomcat.dbcp.pool2.impl;
  * its own specific configuration attributes.
  * <p>
  * This class is immutable and thread-safe.
+ * </p>
  *
  * @since 2.0
  */
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
index 01dc542..93c7a84 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericKeyedObjectPool.java
@@ -17,6 +17,7 @@
 package org.apache.tomcat.dbcp.pool2.impl;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -50,10 +51,12 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectState;
  * {@link #borrowObject borrowObject} methods. Each time a new key value is
  * provided to one of these methods, a sub-new pool is created under the given
  * key to be managed by the containing <code>GenericKeyedObjectPool.</code>
+ * </p>
  * <p>
  * Note that the current implementation uses a ConcurrentHashMap which uses
  * equals() to compare keys.
  * This means that distinct instance keys must be distinguishable using equals.
+ * </p>
  * <p>
  * Optionally, one may configure the pool to examine and possibly evict objects
  * as they sit idle in the pool and to ensure that a minimum number of idle
@@ -62,12 +65,15 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectState;
  * configuring this optional feature. Eviction runs contend with client threads
  * for access to objects in the pool, so if they run too frequently performance
  * issues may result.
+ * </p>
  * <p>
  * Implementation note: To prevent possible deadlocks, care has been taken to
  * ensure that no call to a factory method will occur within a synchronization
  * block. See POOL-125 and DBCP-44 for more information.
+ * </p>
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @see GenericObjectPool
  *
@@ -447,6 +453,11 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
 
         final ObjectDeque<T> objectDeque = poolMap.get(key);
 
+        if (objectDeque == null) {
+            throw new IllegalStateException(
+                    "No keyed pool found under the given key.");
+        }
+
         final PooledObject<T> p = objectDeque.getAllObjects().get(new IdentityWrapper<>(obj));
 
         if (p == null) {
@@ -1077,8 +1088,16 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
         final ObjectDeque<T> objectDeque = register(key);
 
         try {
-            final boolean isIdle = objectDeque.getIdleObjects().remove(toDestroy);
-
+            boolean isIdle;
+            synchronized(toDestroy) {
+                // Check idle state directly
+                isIdle = toDestroy.getState().equals(PooledObjectState.IDLE);
+                // If idle, not under eviction test, or always is true, remove instance,
+                // updating isIdle if instance is found in idle objects
+                if (isIdle || always) {
+                    isIdle = objectDeque.getIdleObjects().remove(toDestroy);
+                }
+            }
             if (isIdle || always) {
                 objectDeque.getAllObjects().remove(new IdentityWrapper<>(toDestroy.getObject()));
                 toDestroy.invalidate();
@@ -1151,10 +1170,9 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
      */
     private void deregister(final K k) {
         Lock lock = keyLock.readLock();
-        ObjectDeque<T> objectDeque;
         try {
             lock.lock();
-            objectDeque = poolMap.get(k);
+            final ObjectDeque<T> objectDeque = poolMap.get(k);
             final long numInterested = objectDeque.getNumInterested().decrementAndGet();
             if (numInterested == 0 && objectDeque.getCreateCount().get() == 0) {
                 // Potential to remove key
@@ -1244,6 +1262,58 @@ public class GenericKeyedObjectPool<K, T> extends BaseGenericObjectPool<T>
     }
 
     /**
+     * Calls {@link KeyedObjectPool#addObject(Object)} with each
+     * key in <code>keys</code> for <code>count</code> number of times. This has
+     * the same effect as calling {@link #addObjects(Object, int)}
+     * for each key in the <code>keys</code> collection.
+     *
+     * @param keys
+     *            {@link Collection} of keys to add objects for.
+     * @param count
+     *            the number of idle objects to add for each <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>keyedPool</code>, <code>keys</code>, or any value
+     *             in <code>keys</code> is <code>null</code>.
+     * @see #addObjects(Object, int)
+     */
+    @Override
+    public void addObjects(final Collection<K> keys, final int count) throws Exception, IllegalArgumentException {
+        if (keys == null) {
+            throw new IllegalArgumentException(PoolUtils.MSG_NULL_KEYS);
+        }
+        final Iterator<K> iter = keys.iterator();
+        while (iter.hasNext()) {
+            addObjects(iter.next(), count);
+        }
+    }
+
+    /**
+     * Calls {@link KeyedObjectPool#addObject(Object)}
+     * <code>key</code> <code>count</code> number of times.
+     *
+     * @param key
+     *            the key to add objects for.
+     * @param count
+     *            the number of idle objects to add for <code>key</code>.
+     * @throws Exception
+     *             when {@link KeyedObjectPool#addObject(Object)} fails.
+     * @throws IllegalArgumentException
+     *             when <code>key</code> is <code>null</code>.
+     * @since 2.8.0
+     */
+    @Override
+    public void addObjects(final K key, final int count) throws Exception, IllegalArgumentException {
+        if (key == null) {
+            throw new IllegalArgumentException(PoolUtils.MSG_NULL_KEY);
+        }
+        for (int i = 0; i < count; i++) {
+            addObject(key);
+        }
+    }
+
+    /**
      * Add an object to the set of idle objects for a given key.
      *
      * @param key The key to associate with the idle object
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
index c72b701..4a9909d 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/GenericObjectPool.java
@@ -38,7 +38,8 @@ import org.apache.tomcat.dbcp.pool2.UsageTracking;
  * <p>
  * When coupled with the appropriate {@link PooledObjectFactory},
  * <code>GenericObjectPool</code> provides robust pooling functionality for
- * arbitrary objects.</p>
+ * arbitrary objects.
+ * </p>
  * <p>
  * Optionally, one may configure the pool to examine and possibly evict objects
  * as they sit idle in the pool and to ensure that a minimum number of idle
@@ -46,7 +47,8 @@ import org.apache.tomcat.dbcp.pool2.UsageTracking;
  * which runs asynchronously. Caution should be used when configuring this
  * optional feature. Eviction runs contend with client threads for access to
  * objects in the pool, so if they run too frequently performance issues may
- * result.</p>
+ * result.
+ * </p>
  * <p>
  * The pool can also be configured to detect and remove "abandoned" objects,
  * i.e. objects that have been checked out of the pool but neither used nor
@@ -59,13 +61,16 @@ import org.apache.tomcat.dbcp.pool2.UsageTracking;
  * their last use will be queried
  * using the <code>getLastUsed</code> method on that interface; otherwise
  * abandonment is determined by how long an object has been checked out from
- * the pool.</p>
+ * the pool.
+ * </p>
  * <p>
  * Implementation note: To prevent possible deadlocks, care has been taken to
  * ensure that no call to a factory method will occur within a synchronization
- * block. See POOL-125 and DBCP-44 for more information.</p>
+ * block. See POOL-125 and DBCP-44 for more information.
+ * </p>
  * <p>
- * This class is intended to be thread-safe.</p>
+ * This class is intended to be thread-safe.
+ * </p>
  *
  * @see GenericKeyedObjectPool
  *
@@ -576,6 +581,11 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
             } catch (final Exception e) {
                 swallowException(e);
             }
+            try {
+                ensureIdle(1, false);
+            } catch (final Exception e) {
+                swallowException(e);
+            }
         } else {
             if (getLifo()) {
                 idleObjects.addFirst(p);
@@ -931,15 +941,6 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
             destroyedCount.incrementAndGet();
             createCount.decrementAndGet();
         }
-
-        if (idleObjects.isEmpty() && idleObjects.hasTakeWaiters()) {
-            // POOL-356.
-            // In case there are already threads waiting on something in the pool
-            // (e.g. idleObjects.takeFirst(); then we need to provide them a fresh instance.
-            // Otherwise they will be stuck forever (or until timeout)
-            final PooledObject<T> freshPooled = create();
-            idleObjects.put(freshPooled);
-        }
     }
 
     @Override
@@ -1005,6 +1006,23 @@ public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
     }
 
     /**
+     * Calls {@link ObjectPool#addObject()} <code>count</code>
+     * number of times.
+     *
+     * @param count
+     *            the number of idle objects to add.
+     * @throws Exception
+     *             when {@link ObjectPool#addObject()} fails.
+     * @since 2.8.0
+     */
+    @Override
+    public void addObjects(final int count) throws Exception {
+        for (int i = 0; i < count; i++) {
+            addObject();
+        }
+    }
+
+    /**
      * Adds the provided wrapped pooled object to the set of idle objects for
      * this pool. The object must already be part of the pool.  If {@code p}
      * is null, this is a no-op (no exception, but no impact on the pool).
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java b/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
index 5a51b92..b539aed 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/InterruptibleReentrantLock.java
@@ -26,6 +26,7 @@ import java.util.concurrent.locks.ReentrantLock;
  * class is intended for internal use only.
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @since 2.0
  */
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java b/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
index be92f91..75e925e 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/LinkedBlockingDeque.java
@@ -34,6 +34,7 @@ import java.util.concurrent.locks.Condition;
  * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
  * dynamically created upon each insertion unless this would bring the
  * deque above capacity.
+ * </p>
  *
  * <p>Most operations run in constant time (ignoring time spent
  * blocking).  Exceptions include {@link #remove(Object) remove},
@@ -41,14 +42,17 @@ import java.util.concurrent.locks.Condition;
  * #removeLastOccurrence removeLastOccurrence}, {@link #contains
  * contains}, {@link #iterator iterator.remove()}, and the bulk
  * operations, all of which run in linear time.
+ * </p>
  *
  * <p>This class and its iterator implement all of the
  * <em>optional</em> methods of the {@link Collection} and {@link
  * Iterator} interfaces.
+ * </p>
  *
  * <p>This class is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
+ * </p>
  *
  * @param <E> the type of elements held in this collection
  *
diff --git a/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java b/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
index 61741be..e417b48 100644
--- a/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
+++ b/java/org/apache/tomcat/dbcp/pool2/impl/SoftReferenceObjectPool.java
@@ -32,6 +32,7 @@ import org.apache.tomcat.dbcp.pool2.PooledObjectFactory;
  * {@link org.apache.tomcat.dbcp.pool2.ObjectPool}.
  * <p>
  * This class is intended to be thread-safe.
+ * </p>
  *
  * @param <T>
  *            Type of element pooled in this pool.
@@ -185,6 +186,8 @@ public class SoftReferenceObjectPool<T> extends BaseObjectPool<T> {
      *
      * @param obj
      *            instance to return to the pool
+     * @throws IllegalArgumentException
+     *            if obj is not currently part of this pool
      */
     @Override
     public synchronized void returnObject(final T obj) throws Exception {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 9b8c487..86adeab 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -213,6 +213,10 @@
         Update the internal fork of Apache Commons FileUpload to 2317552
         (2019-12-06, 2.0-SNAPSHOT). Refactoring. (markt)
       </add>
+      <add>
+        Update the internal fork of Apache Commons Pool 2 to 6092f92 (2019-12-06,
+        2.8.0-SNAPSHOT). Clean-up and minor refactoring. (markt)
+      </add>
     </changelog>
   </subsection>
 </section>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org