I will update Javadoc and add inline comments.

Gary


On Sun, Jun 27, 2021, 11:49 Phil Steitz <phil.ste...@gmail.com> wrote:

> It's hard to tell what the actual change is below with all of the
> formatting / cosmetic changes mixed it, but AFAICT there is no sync
> control to ensure consistency or currency of the stats reported. Some
> note in javadoc or somewhere should be added to make it clear that stats
> may not accurately reflect snapshot state at the time of the exception.
> If you want to get a guaranteed accurate snapshot, you would have to
> lock the pool when you take it, which we don't want to do.
>
> On 6/27/21 7:47 AM, ggreg...@apache.org wrote:
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > ggregory pushed a commit to branch master
> > in repository https://gitbox.apache.org/repos/asf/commons-pool.git
> >
> >
> > The following commit(s) were added to refs/heads/master by this push:
> >       new 26b0829  [POOL-395] Improve exception thrown in
> GenericObjectPool.borrowObject when pool is exhausted. Added
> BaseGenericObjectPool.setMessagesStatistics(boolean).
> > 26b0829 is described below
> >
> > commit 26b0829fef39729df84adb1c01eb55c944aff6d7
> > Author: Gary Gregory <garydgreg...@gmail.com>
> > AuthorDate: Sun Jun 27 10:47:03 2021 -0400
> >
> >      [POOL-395] Improve exception thrown in
> GenericObjectPool.borrowObject
> >      when pool is exhausted. Added
> >      BaseGenericObjectPool.setMessagesStatistics(boolean).
> >
> >      - Pick up Checkstyle LineLength module from Commons IO where there
> was
> >      none before.
> >      - Message sentences start with a capital letter.
> >      - Better parameter names.
> >      - Javadoc.
> >      - Inline comments.
> > ---
> >   checkstyle.xml                                     |   4 +
> >   src/changes/changes.xml                            |   3 +
> >   .../org/apache/commons/pool2/KeyedObjectPool.java  |   4 +-
> >   .../commons/pool2/KeyedPooledObjectFactory.java    |   4 +-
> >   .../java/org/apache/commons/pool2/ObjectPool.java  |   4 +-
> >   .../apache/commons/pool2/PooledObjectFactory.java  |   4 +-
> >   .../commons/pool2/impl/BaseGenericObjectPool.java  | 114
> ++++++++++++++++-----
> >   .../commons/pool2/impl/GenericKeyedObjectPool.java |  48 +++++----
> >   .../commons/pool2/impl/GenericObjectPool.java      |  46 +++++----
> >   .../pool2/impl/SoftReferenceObjectPool.java        |   4 +-
> >   .../pool2/TestBasePoolableObjectFactory.java       |   4 +-
> >   .../pool2/impl/TestAbandonedKeyedObjectPool.java   |   4 +-
> >   .../pool2/impl/TestAbandonedObjectPool.java        |   4 +-
> >   .../pool2/impl/TestGenericKeyedObjectPool.java     |  64 +++++++-----
> >   .../commons/pool2/impl/TestGenericObjectPool.java  |  28 ++++-
> >   15 files changed, 230 insertions(+), 109 deletions(-)
> >
> > diff --git a/checkstyle.xml b/checkstyle.xml
> > index dca770b..3f884e1 100644
> > --- a/checkstyle.xml
> > +++ b/checkstyle.xml
> > @@ -74,4 +74,8 @@
> >       <property name="allowLegacy" value="true"/>
> >     </module>
> >
> > +  <module name="LineLength">
> > +    <property name="max" value="160"/>
> > +  </module>
> > +
> >   </module>
> > diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> > index 40ef624..2368098 100644
> > --- a/src/changes/changes.xml
> > +++ b/src/changes/changes.xml
> > @@ -69,6 +69,9 @@ The <action> type attribute can be
> add,update,fix,remove.
> >       <action issue="POOL-396" dev="ggregory" type="add" due-to="Jeremy
> Kong, Phil Steitz">
> >         Handle validation exceptions during eviction. #85.
> >       </action>
> > +    <action issue="POOL-395" dev="ggregory" type="add" due-to="Gary
> Gregory, Arash Nikoo">
> > +      Improve exception thrown in GenericObjectPool.borrowObject when
> pool is exhausted. Added
> BaseGenericObjectPool.setMessagesStatistics(boolean).
> > +    </action>
> >       <!-- FIXES -->
> >       <action dev="ggregory" type="fix" due-to="Gary Gregory">
> >         Fix [WARNING] Old version of checkstyle detected. Consider
> updating to >= v8.30. Update Checktyle to 8.43.
> > diff --git a/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
> b/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
> > index ab52908..cac55ac 100644
> > --- a/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
> > +++ b/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
> > @@ -289,12 +289,12 @@ public interface KeyedObjectPool<K, V> extends
> Closeable {
> >        *
> >        * @param key the key used to obtain the object
> >        * @param obj a {@link #borrowObject borrowed} instance to be
> returned.
> > -     * @param mode destroy activation context provided to the factory
> > +     * @param destroyMode destroy activation context provided to the
> factory
> >        *
> >        * @throws Exception if the instance cannot be invalidated
> >        * @since 2.9.0
> >        */
> > -    default void invalidateObject(final K key, final V obj, final
> DestroyMode mode) throws Exception {
> > +    default void invalidateObject(final K key, final V obj, final
> DestroyMode destroyMode) throws Exception {
> >           invalidateObject(key, obj);
> >       }
> >
> > diff --git
> a/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
> b/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
> > index ac93114..a7f75a3 100644
> > ---
> a/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
> > +++
> b/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
> > @@ -117,7 +117,7 @@ public interface KeyedPooledObjectFactory<K, V> {
> >        *
> >        * @param key the key used when selecting the instance
> >        * @param p a {@code PooledObject} wrapping the instance to be
> destroyed
> > -     * @param mode DestroyMode providing context to the factory
> > +     * @param destroyMode DestroyMode providing context to the factory
> >        *
> >        * @throws Exception should be avoided as it may be swallowed by
> >        *    the pool implementation.
> > @@ -128,7 +128,7 @@ public interface KeyedPooledObjectFactory<K, V> {
> >        * @see DestroyMode
> >        * @since 2.9.0
> >        */
> > -    default void destroyObject(final K key, final PooledObject<V> p,
> final DestroyMode mode) throws Exception {
> > +    default void destroyObject(final K key, final PooledObject<V> p,
> final DestroyMode destroyMode) throws Exception {
> >           destroyObject(key, p);
> >       }
> >
> > diff --git a/src/main/java/org/apache/commons/pool2/ObjectPool.java
> b/src/main/java/org/apache/commons/pool2/ObjectPool.java
> > index 8225d27..8aa2d58 100644
> > --- a/src/main/java/org/apache/commons/pool2/ObjectPool.java
> > +++ b/src/main/java/org/apache/commons/pool2/ObjectPool.java
> > @@ -198,12 +198,12 @@ public interface ObjectPool<T> extends Closeable {
> >        * </p>
> >        *
> >        * @param obj a {@link #borrowObject borrowed} instance to be
> disposed.
> > -     * @param mode destroy activation context provided to the factory
> > +     * @param destroyMode destroy activation context provided to the
> factory
> >        *
> >        * @throws Exception if the instance cannot be invalidated
> >        * @since 2.9.0
> >        */
> > -    default void invalidateObject(final T obj, final DestroyMode mode)
> throws Exception {
> > +    default void invalidateObject(final T obj, final DestroyMode
> destroyMode) throws Exception {
> >           invalidateObject(obj);
> >       }
> >
> > diff --git
> a/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
> b/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
> > index 009f341..839e866 100644
> > --- a/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
> > +++ b/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
> > @@ -112,7 +112,7 @@ public interface PooledObjectFactory<T> {
> >      * DestroyMode.
> >      *
> >      * @param p a {@code PooledObject} wrapping the instance to be
> destroyed
> > -   * @param mode DestroyMode providing context to the factory
> > +   * @param destroyMode DestroyMode providing context to the factory
> >      *
> >      * @throws Exception should be avoided as it may be swallowed by
> >      *    the pool implementation.
> > @@ -123,7 +123,7 @@ public interface PooledObjectFactory<T> {
> >      * @see DestroyMode
> >      * @since 2.9.0
> >      */
> > -  default void destroyObject(final PooledObject<T> p, final DestroyMode
> mode) throws Exception {
> > +  default void destroyObject(final PooledObject<T> p, final DestroyMode
> destroyMode) throws Exception {
> >         destroyObject(p);
> >     }
> >
> > diff --git
> a/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
> b/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
> > index 000a6eb..83f37e1 100644
> > ---
> a/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
> > +++
> b/src/main/java/org/apache/commons/pool2/impl/BaseGenericObjectPool.java
> > @@ -26,9 +26,11 @@ import java.time.Duration;
> >   import java.util.Arrays;
> >   import java.util.Deque;
> >   import java.util.Iterator;
> > +import java.util.List;
> >   import java.util.TimerTask;
> >   import java.util.concurrent.ScheduledFuture;
> >   import java.util.concurrent.atomic.AtomicLong;
> > +import java.util.stream.Collectors;
> >
> >   import javax.management.InstanceAlreadyExistsException;
> >   import javax.management.InstanceNotFoundException;
> > @@ -233,12 +235,14 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >               return builder.toString();
> >           }
> >       }
> > +
> >       /**
> >        * Maintains a cache of values for a single metric and reports
> >        * statistics on the cached values.
> >        */
> >       private class StatsStore {
> >
> > +        private static final int NULL = -1;
> >           private final AtomicLong[] values;
> >           private final int size;
> >           private int index;
> > @@ -252,7 +256,7 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >               this.size = size;
> >               values = new AtomicLong[size];
> >               for (int i = 0; i < size; i++) {
> > -                values[i] = new AtomicLong(-1);
> > +                values[i] = new AtomicLong(NULL);
> >               }
> >           }
> >
> > @@ -275,6 +279,15 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >           }
> >
> >           /**
> > +         * Gets the current values as a List.
> > +         *
> > +         * @return the current values as a List.
> > +         */
> > +        synchronized List<AtomicLong> getCurrentValues() {
> > +            return Arrays.stream(values, 0,
> index).collect(Collectors.toList());
> > +        }
> > +
> > +        /**
> >            * Gets the mean of the cached values.
> >            *
> >            * @return the mean of the cache, truncated to long
> > @@ -284,10 +297,9 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >               int counter = 0;
> >               for (int i = 0; i < size; i++) {
> >                   final long value = values[i].get();
> > -                if (value != -1) {
> > +                if (value != NULL) {
> >                       counter++;
> > -                    result = result * ((counter - 1) / (double)
> counter) +
> > -                            value/(double) counter;
> > +                    result = result * ((counter - 1) / (double)
> counter) + value / (double) counter;
> >                   }
> >               }
> >               return (long) result;
> > @@ -296,16 +308,19 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >           @Override
> >           public String toString() {
> >               final StringBuilder builder = new StringBuilder();
> > -            builder.append("StatsStore [values=");
> > -            builder.append(Arrays.toString(values));
> > -            builder.append(", size=");
> > +            builder.append("StatsStore [");
> > +            // Only append what's been filled in.
> > +            builder.append(getCurrentValues());
> > +            builder.append("], size=");
> >               builder.append(size);
> >               builder.append(", index=");
> >               builder.append(index);
> >               builder.append("]");
> >               return builder.toString();
> >           }
> > +
> >       }
> > +
> >       // Constants
> >       /**
> >        * The size of the caches used to store historical data for some
> attributes
> > @@ -334,7 +349,6 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       final Object closeLock = new Object();
> >       volatile boolean closed;
> >
> > -
> >       final Object evictionLock = new Object();
> >       private Evictor evictor = null; // @GuardedBy("evictionLock")
> >       EvictionIterator evictionIterator = null; //
> @GuardedBy("evictionLock")
> > @@ -348,21 +362,21 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       // Monitoring (primarily JMX) attributes
> >       private final ObjectName objectName;
> >       private final String creationStackTrace;
> > -    private final AtomicLong borrowedCount = new AtomicLong(0);
> > -    private final AtomicLong returnedCount = new AtomicLong(0);
> > -    final AtomicLong createdCount = new AtomicLong(0);
> > -    final AtomicLong destroyedCount = new AtomicLong(0);
> > -    final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
> > -    final AtomicLong destroyedByBorrowValidationCount = new
> AtomicLong(0);
> > +    private final AtomicLong borrowedCount = new AtomicLong();
> > +    private final AtomicLong returnedCount = new AtomicLong();
> > +    final AtomicLong createdCount = new AtomicLong();
> > +    final AtomicLong destroyedCount = new AtomicLong();
> > +    final AtomicLong destroyedByEvictorCount = new AtomicLong();
> > +    final AtomicLong destroyedByBorrowValidationCount = new
> AtomicLong();
> > +
> >       private final StatsStore activeTimes = new
> StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
> > -
> >       private final StatsStore idleTimes = new
> StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
> > -
> >       private final StatsStore waitTimes = new
> StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
> >
> > -    private final AtomicLong maxBorrowWaitTimeMillis = new
> AtomicLong(0L);
> > +    private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong();
> >
> > -    private volatile SwallowedExceptionListener
> swallowedExceptionListener = null;
> > +    private volatile SwallowedExceptionListener
> swallowedExceptionListener;
> > +    private volatile boolean messageStatistics;
> >
> >       /**
> >        * Handles JMX registration (if required) and the initialization
> required for
> > @@ -396,6 +410,16 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       }
> >
> >       /**
> > +     * Appends statistics if enabled.
> > +     *
> > +     * @param string The root string.
> > +     * @return The root string plus statistics.
> > +     */
> > +    String appendStats(final String string) {
> > +        return messageStatistics ? string + ", " + getStatsString() :
> string;
> > +    }
> > +
> > +    /**
> >        * Verifies that the pool is open.
> >        * @throws IllegalStateException if the pool is closed.
> >        */
> > @@ -680,6 +704,16 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       }
> >
> >       /**
> > +     * Gets whether to include statistics in exception messages.
> > +     *
> > +     * @return whether to include statistics in exception messages.
> > +     * @since 2.11.0
> > +     */
> > +    public boolean getMessageStatistics() {
> > +        return messageStatistics;
> > +    }
> > +
> > +    /**
> >        * Gets the minimum amount of time an object may sit idle in the
> pool
> >        * before it is eligible for eviction by the idle object evictor
> (if any -
> >        * see {@link #setTimeBetweenEvictionRuns(Duration)}). When
> non-positive,
> > @@ -806,6 +840,22 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       }
> >
> >       /**
> > +     * Gets a statistics string.
> > +     *
> > +     * @return  a statistics string.
> > +     */
> > +    String getStatsString() {
> > +        // Simply listed in AB order.
> > +        return String.format(
> > +                "activeTimes=%s, blockWhenExhausted=%s,
> borrowedCount=%,d, closed=%s, createdCount=%,d,
> destroyedByBorrowValidationCount=%,d, destroyedByEvictorCount=%,d,
> evictorShutdownTimeout=%s, fairness=%s, idleTimes=%s, lifo=%s,
> maxBorrowWaitTimeMillis=%,d, maxTotal=%s, maxWaitDuration=%s,
> minEvictableIdleTime=%s, numTestsPerEvictionRun=%s, returnedCount=%s,
> softMinEvictableIdleTime=%s, testOnBorrow=%s, testOnCreate=%s,
> testOnReturn=%s, testWhileIdle=%s, timeBetweenEvictionRuns=%s,  [...]
> > +                activeTimes.getCurrentValues(), blockWhenExhausted,
> borrowedCount.get(), closed, createdCount.get(),
> > +                destroyedByBorrowValidationCount.get(),
> destroyedByEvictorCount.get(), evictorShutdownTimeout, fairness,
> > +                idleTimes.getCurrentValues(), lifo,
> maxBorrowWaitTimeMillis.get(), maxTotal, maxWaitDuration,
> > +                minEvictableIdleTime, numTestsPerEvictionRun,
> returnedCount, softMinEvictableIdleTime, testOnBorrow,
> > +                testOnCreate, testOnReturn, testWhileIdle,
> timeBetweenEvictionRuns, waitTimes.getCurrentValues());
> > +    }
> > +
> > +    /**
> >        * The listener used (if any) to receive notifications of
> exceptions
> >        * unavoidably swallowed by the pool.
> >        *
> > @@ -984,8 +1034,7 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       final void jmxUnregister() {
> >           if (objectName != null) {
> >               try {
> > -
> ManagementFactory.getPlatformMBeanServer().unregisterMBean(
> > -                        objectName);
> > +
> ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName);
> >               } catch (final MBeanRegistrationException |
> InstanceNotFoundException e) {
> >                   swallowException(e);
> >               }
> > @@ -997,10 +1046,9 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >        * @param pooledObject instance to return to the keyed pool
> >        */
> >       protected void markReturningState(final PooledObject<T>
> pooledObject) {
> > -        synchronized(pooledObject) {
> > +        synchronized (pooledObject) {
> >               if (pooledObject.getState() !=
> PooledObjectState.ALLOCATED) {
> > -                throw new IllegalStateException(
> > -                        "Object has already been returned to this pool
> or is invalid");
> > +                throw new IllegalStateException("Object has already
> been returned to this pool or is invalid");
> >               }
> >               pooledObject.markReturning(); // Keep from being marked
> abandoned
> >           }
> > @@ -1121,9 +1169,9 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >                       classLoader + ", " + epClassLoader + "] do not
> implement " + EVICTION_POLICY_TYPE_NAME);
> >           } catch (final ClassNotFoundException | InstantiationException
> | IllegalAccessException |
> >                   InvocationTargetException | NoSuchMethodException e) {
> > -            final String exMessage = "Unable to create " +
> EVICTION_POLICY_TYPE_NAME + " instance of type " +
> > -                    evictionPolicyClassName;
> > -            throw new IllegalArgumentException(exMessage, e);
> > +            throw new IllegalArgumentException(
> > +                    "Unable to create " + EVICTION_POLICY_TYPE_NAME + "
> instance of type " + evictionPolicyClassName,
> > +                    e);
> >           }
> >       }
> >
> > @@ -1223,6 +1271,16 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >       }
> >
> >       /**
> > +     * Sets whether to include statistics in exception messages.
> > +     *
> > +     * @param messagesDetails whether to include statistics in
> exception messages.
> > +     * @since 2.11.0
> > +     */
> > +    public void setMessagesStatistics(boolean messagesDetails) {
> > +        this.messageStatistics = messagesDetails;
> > +    }
> > +
> > +    /**
> >        * Sets the minimum amount of time an object may sit idle in the
> pool
> >        * before it is eligible for eviction by the idle object evictor
> (if any -
> >        * see {@link #setTimeBetweenEvictionRuns(Duration)}). When
> non-positive,
> > @@ -1446,6 +1504,8 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >
>  setTimeBetweenEvictionRuns(Duration.ofMillis(timeBetweenEvictionRunsMillis));
> >       }
> >
> > +    // Inner classes
> > +
> >       /**
> >        * <p>Starts the evictor with the given delay. If there is an
> evictor
> >        * running when this method is called, it is stopped and replaced
> with a
> > @@ -1478,8 +1538,6 @@ public abstract class BaseGenericObjectPool<T>
> extends BaseObject {
> >           }
> >       }
> >
> > -    // Inner classes
> > -
> >       /**
> >        * Stops the evictor.
> >        */
> > diff --git
> a/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> b/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> > index 11fd633..64274bd 100644
> > ---
> a/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> > +++
> b/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
> > @@ -121,7 +121,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >            * Invariant: empty keyed pool will not be dropped unless
> numInterested
> >            *            is 0.
> >            */
> > -        private final AtomicLong numInterested = new AtomicLong(0);
> > +        private final AtomicLong numInterested = new AtomicLong();
> >
> >           /**
> >            * Constructs a new ObjecDeque with the given fairness policy.
> > @@ -267,7 +267,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >
> >           if (factory == null) {
> >               jmxUnregister(); // tidy up
> > -            throw new IllegalArgumentException("factory may not be
> null");
> > +            throw new IllegalArgumentException("Factory may not be
> null");
> >           }
> >           this.factory = factory;
> >           this.fairness = config.getFairness();
> > @@ -449,16 +449,15 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >                           if (borrowMaxWaitMillis < 0) {
> >                               p =
> objectDeque.getIdleObjects().takeFirst();
> >                           } else {
> > -                            p = objectDeque.getIdleObjects().pollFirst(
> > -                                    borrowMaxWaitMillis,
> TimeUnit.MILLISECONDS);
> > +                            p =
> objectDeque.getIdleObjects().pollFirst(borrowMaxWaitMillis,
> TimeUnit.MILLISECONDS);
> >                           }
> >                       }
> >                       if (p == null) {
> > -                        throw new NoSuchElementException(
> > -                                "Timeout waiting for idle object");
> > +                        throw new NoSuchElementException(appendStats(
> > +                                "Timeout waiting for idle object,
> borrowMaxWaitMillis=" + borrowMaxWaitMillis));
> >                       }
> >                   } else if (p == null) {
> > -                    throw new NoSuchElementException("Pool exhausted");
> > +                    throw new NoSuchElementException(appendStats("Pool
> exhausted"));
> >                   }
> >                   if (!p.allocate()) {
> >                       p = null;
> > @@ -475,8 +474,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >                           }
> >                           p = null;
> >                           if (create) {
> > -                            final NoSuchElementException nsee = new
> NoSuchElementException(
> > -                                    "Unable to activate object");
> > +                            final NoSuchElementException nsee = new
> NoSuchElementException(appendStats("Unable to activate object"));
> >                               nsee.initCause(e);
> >                               throw nsee;
> >                           }
> > @@ -500,7 +498,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >                               p = null;
> >                               if (create) {
> >                                   final NoSuchElementException nsee =
> new NoSuchElementException(
> > -                                        "Unable to validate object");
> > +                                        appendStats("Unable to validate
> object"));
> >                                   nsee.initCause(validationThrowable);
> >                                   throw nsee;
> >                               }
> > @@ -517,6 +515,13 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >           return p.getObject();
> >       }
> >
> > +    @Override
> > +    String getStatsString() {
> > +        // Simply listed in AB order.
> > +        return super.getStatsString() +
> > +                String.format(", fairness=%s, maxIdlePerKey%,d,
> maxTotalPerKey=%,d, minIdlePerKey=%,d, numTotal=%,d",
> > +                        fairness, maxIdlePerKey, maxTotalPerKey,
> minIdlePerKey, numTotal.get());
> > +    }
> >
> >       /**
> >        * Calculate the number of objects that need to be created to
> attempt to
> > @@ -820,7 +825,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >       /**
> >        * De-register the use of a key by an object.
> >        * <p>
> > -     * register() and deregister() must always be used as a pair.
> > +     * {@link #register()} and {@link #deregister()} must always be
> used as a pair.
> >        * </p>
> >        *
> >        * @param k The key to de-register
> > @@ -858,12 +863,12 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >        * @param toDestroy The wrapped object to be destroyed
> >        * @param always Should the object be destroyed even if it is not
> currently
> >        *               in the set of idle objects for the given key
> > -     * @param mode DestroyMode context provided to the factory
> > +     * @param destroyMode DestroyMode context provided to the factory
> >        *
> >        * @return {@code true} if the object was destroyed, otherwise
> {@code false}
> >        * @throws Exception If the object destruction failed
> >        */
> > -    private boolean destroy(final K key, final PooledObject<T>
> toDestroy, final boolean always, final DestroyMode mode)
> > +    private boolean destroy(final K key, final PooledObject<T>
> toDestroy, final boolean always, final DestroyMode destroyMode)
> >               throws Exception {
> >
> >           final ObjectDeque<T> objectDeque = register(key);
> > @@ -884,7 +889,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >                   toDestroy.invalidate();
> >
> >                   try {
> > -                    factory.destroyObject(key, toDestroy, mode);
> > +                    factory.destroyObject(key, toDestroy, destroyMode);
> >                   } finally {
> >                       objectDeque.getCreateCount().decrementAndGet();
> >                       destroyedCount.incrementAndGet();
> > @@ -1414,7 +1419,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >        *
> >        * @param key pool key
> >        * @param obj instance to invalidate
> > -     * @param mode DestroyMode context provided to factory
> > +     * @param destroyMode DestroyMode context provided to factory
> >        *
> >        * @throws Exception             if an exception occurs destroying
> the
> >        *                               object
> > @@ -1423,15 +1428,15 @@ public class GenericKeyedObjectPool<K, T>
> extends BaseGenericObjectPool<T>
> >        * @since 2.9.0
> >        */
> >       @Override
> > -    public void invalidateObject(final K key, final T obj, final
> DestroyMode mode) throws Exception {
> > +    public void invalidateObject(final K key, final T obj, final
> DestroyMode destroyMode) throws Exception {
> >           final ObjectDeque<T> objectDeque = poolMap.get(key);
> >           final PooledObject<T> p = objectDeque.getAllObjects().get(new
> IdentityWrapper<>(obj));
> >           if (p == null) {
> > -            throw new IllegalStateException("Object not currently part
> of this pool");
> > +            throw new IllegalStateException(appendStats("Object not
> currently part of this pool"));
> >           }
> >           synchronized (p) {
> >               if (p.getState() != PooledObjectState.INVALID) {
> > -                destroy(key, p, true, mode);
> > +                destroy(key, p, true, destroyMode);
> >               }
> >           }
> >           if (objectDeque.idleObjects.hasTakeWaiters()) {
> > @@ -1502,7 +1507,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >       /**
> >        * Register the use of a key by an object.
> >        * <p>
> > -     * register() and deregister() must always be used as a pair.
> > +     * {@link #register()} and {@link #deregister()} must always be
> used as a pair.
> >        * </p>
> >        *
> >        * @param k The key to register
> > @@ -1579,6 +1584,7 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >                   try {
> >                       invalidateObject(pool.getKey(),
> pooledObject.getObject(), DestroyMode.ABANDONED);
> >                   } catch (final Exception e) {
> > +                    // TODO handle/log?
> >                       e.printStackTrace();
> >                   }
> >               }
> > @@ -1828,9 +1834,9 @@ public class GenericKeyedObjectPool<K, T> extends
> BaseGenericObjectPool<T>
> >        *
> >        * @param minIdlePerKey The minimum size of the each keyed pool
> >        *
> > -     * @see #getMinIdlePerKey
> > +     * @see #getMinIdlePerKey()
> >        * @see #getMaxIdlePerKey()
> > -     * @see #setTimeBetweenEvictionRunsMillis
> > +     * @see #setTimeBetweenEvictionRuns(Duration)
> >        */
> >       public void setMinIdlePerKey(final int minIdlePerKey) {
> >           this.minIdlePerKey = minIdlePerKey;
> > diff --git
> a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> > index ee27b58..c5fed24 100644
> > --- a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> > +++ b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
> > @@ -115,7 +115,7 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >        * {@link #create()} will ensure that there are never more than
> >        * {@link #_maxActive} objects created at any one time.
> >        */
> > -    private final AtomicLong createCount = new AtomicLong(0);
> > +    private final AtomicLong createCount = new AtomicLong();
> >
> >       private long makeObjectCount;
> >
> > @@ -155,7 +155,7 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >
> >           if (factory == null) {
> >               jmxUnregister(); // tidy up
> > -            throw new IllegalArgumentException("factory may not be
> null");
> > +            throw new IllegalArgumentException("Factory may not be
> null");
> >           }
> >           this.factory = factory;
> >
> > @@ -214,8 +214,7 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >       public void addObject() throws Exception {
> >           assertOpen();
> >           if (factory == null) {
> > -            throw new IllegalStateException(
> > -                    "Cannot add objects without a factory.");
> > +            throw new IllegalStateException("Cannot add objects without
> a factory.");
> >           }
> >           final PooledObject<T> p = create();
> >           addIdleObject(p);
> > @@ -271,7 +270,7 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >        * available instances in request arrival order.
> >        * </p>
> >        *
> > -     * @param borrowMaxWait The time to wait for an object
> > +     * @param borrowMaxWaitDuration The time to wait for an object
> >        *                            to become available
> >        *
> >        * @return object instance from the pool
> > @@ -282,11 +281,11 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >        *                   error
> >        * @since 2.10.0
> >        */
> > -    public T borrowObject(final Duration borrowMaxWait) throws
> Exception {
> > +    public T borrowObject(final Duration borrowMaxWaitDuration) throws
> Exception {
> >           assertOpen();
> >
> >           final AbandonedConfig ac = this.abandonedConfig;
> > -        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
> (getNumIdle() < 2) &&
> > +        if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
> (getNumIdle() < 2) &&
> >                   (getNumActive() > getMaxTotal() - 3)) {
> >               removeAbandoned(ac);
> >           }
> > @@ -311,17 +310,18 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >               }
> >               if (blockWhenExhausted) {
> >                   if (p == null) {
> > -                    if (borrowMaxWait.isNegative()) {
> > +                    if (borrowMaxWaitDuration.isNegative()) {
> >                           p = idleObjects.takeFirst();
> >                       } else {
> > -                        p = idleObjects.pollFirst(borrowMaxWait);
> > +                        p =
> idleObjects.pollFirst(borrowMaxWaitDuration);
> >                       }
> >                   }
> >                   if (p == null) {
> > -                    throw new NoSuchElementException("Timeout waiting
> for idle object");
> > +                    throw new NoSuchElementException(appendStats(
> > +                            "Timeout waiting for idle object,
> borrowMaxWaitMillis=" + borrowMaxWaitDuration));
> >                   }
> >               } else if (p == null) {
> > -                throw new NoSuchElementException("Pool exhausted");
> > +                throw new NoSuchElementException(appendStats("Pool
> exhausted"));
> >               }
> >               if (!p.allocate()) {
> >                   p = null;
> > @@ -338,7 +338,8 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >                       }
> >                       p = null;
> >                       if (create) {
> > -                        final NoSuchElementException nsee = new
> NoSuchElementException("Unable to activate object");
> > +                        final NoSuchElementException nsee = new
> NoSuchElementException(
> > +                                appendStats("Unable to activate
> object"));
> >                           nsee.initCause(e);
> >                           throw nsee;
> >                       }
> > @@ -361,7 +362,8 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >                           }
> >                           p = null;
> >                           if (create) {
> > -                            final NoSuchElementException nsee = new
> NoSuchElementException("Unable to validate object");
> > +                            final NoSuchElementException nsee = new
> NoSuchElementException(
> > +                                    appendStats("Unable to validate
> object"));
> >                               nsee.initCause(validationThrowable);
> >                               throw nsee;
> >                           }
> > @@ -375,6 +377,14 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >           return p.getObject();
> >       }
> >
> > +    @Override
> > +    String getStatsString() {
> > +        // Simply listed in AB order.
> > +        return super.getStatsString() +
> > +                String.format(", createdCount=%,d, makeObjectCount=%,d,
> maxIdle=%,d, minIdle=%,d",
> > +                        createdCount.get(), makeObjectCount, maxIdle,
> minIdle);
> > +    }
> > +
> >       /**
> >        * Borrows an object from the pool using the specific waiting time
> which only
> >        * applies if {@link #getBlockWhenExhausted()} is true.
> > @@ -592,17 +602,17 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >        * Destroys a wrapped pooled object.
> >        *
> >        * @param toDestroy The wrapped pooled object to destroy
> > -     * @param mode DestroyMode context provided to the factory
> > +     * @param destroyMode DestroyMode context provided to the factory
> >        *
> >        * @throws Exception If the factory fails to destroy the pooled
> object
> >        *                   cleanly
> >        */
> > -    private void destroy(final PooledObject<T> toDestroy, final
> DestroyMode mode) throws Exception {
> > +    private void destroy(final PooledObject<T> toDestroy, final
> DestroyMode destroyMode) throws Exception {
> >           toDestroy.invalidate();
> >           idleObjects.remove(toDestroy);
> >           allObjects.remove(new
> IdentityWrapper<>(toDestroy.getObject()));
> >           try {
> > -            factory.destroyObject(toDestroy, mode);
> > +            factory.destroyObject(toDestroy, destroyMode);
> >           } finally {
> >               destroyedCount.incrementAndGet();
> >               createCount.decrementAndGet();
> > @@ -1002,7 +1012,7 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >        * @since 2.9.0
> >        */
> >       @Override
> > -    public void invalidateObject(final T obj, final DestroyMode mode)
> throws Exception {
> > +    public void invalidateObject(final T obj, final DestroyMode
> destroyMode) throws Exception {
> >           final PooledObject<T> p = allObjects.get(new
> IdentityWrapper<>(obj));
> >           if (p == null) {
> >               if (isAbandonedConfig()) {
> > @@ -1013,7 +1023,7 @@ public class GenericObjectPool<T> extends
> BaseGenericObjectPool<T>
> >           }
> >           synchronized (p) {
> >               if (p.getState() != PooledObjectState.INVALID) {
> > -                destroy(p, mode);
> > +                destroy(p, destroyMode);
> >               }
> >           }
> >           ensureIdle(1, false);
> > diff --git
> a/src/main/java/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java
> b/src/main/java/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java
> > index 849629f..f7c271c 100644
> > ---
> a/src/main/java/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java
> > +++
> b/src/main/java/org/apache/commons/pool2/impl/SoftReferenceObjectPool.java
> > @@ -216,9 +216,7 @@ public class SoftReferenceObjectPool<T> extends
> BaseObjectPool<T> {
> >                           obj = null;
> >                       }
> >                       if (newlyCreated) {
> > -                        throw new NoSuchElementException(
> > -                                "Could not create a validated object,
> cause: " +
> > -                                        t.getMessage());
> > +                        throw new NoSuchElementException("Could not
> create a validated object, cause: " + t);
> >                       }
> >                   }
> >               }
> > diff --git
> a/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
> b/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
> > index 97c411e..43935d5 100644
> > ---
> a/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
> > +++
> b/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
> > @@ -34,8 +34,8 @@ public class TestBasePoolableObjectFactory {
> >               return new AtomicInteger(0);
> >           }
> >           @Override
> > -        public void destroyObject(final PooledObject<AtomicInteger> p,
> final DestroyMode mode){
> > -            if (mode.equals(DestroyMode.ABANDONED)) {
> > +        public void destroyObject(final PooledObject<AtomicInteger> p,
> final DestroyMode destroyMode){
> > +            if (destroyMode.equals(DestroyMode.ABANDONED)) {
> >                   p.getObject().incrementAndGet();
> >               }
> >           }
> > diff --git
> a/src/test/java/org/apache/commons/pool2/impl/TestAbandonedKeyedObjectPool.java
> b/src/test/java/org/apache/commons/pool2/impl/TestAbandonedKeyedObjectPool.java
> > index 541e1ea..0d850c9 100644
> > ---
> a/src/test/java/org/apache/commons/pool2/impl/TestAbandonedKeyedObjectPool.java
> > +++
> b/src/test/java/org/apache/commons/pool2/impl/TestAbandonedKeyedObjectPool.java
> > @@ -103,7 +103,7 @@ public class TestAbandonedKeyedObjectPool {
> >           }
> >
> >           @Override
> > -        public void destroyObject(final Integer key, final
> PooledObject<PooledTestObject> obj, final DestroyMode mode) throws
> Exception {
> > +        public void destroyObject(final Integer key, final
> PooledObject<PooledTestObject> obj, final DestroyMode destroyMode) throws
> Exception {
> >               obj.getObject().setActive(false);
> >               // while destroying instances, yield control to other
> threads
> >               // helps simulate threading errors
> > @@ -111,7 +111,7 @@ public class TestAbandonedKeyedObjectPool {
> >               if (destroyLatency != 0) {
> >                   Thread.sleep(destroyLatency);
> >               }
> > -            obj.getObject().destroy(mode);
> > +            obj.getObject().destroy(destroyMode);
> >           }
> >
> >           @Override
> > diff --git
> a/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
> b/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
> > index 14b264c..9b64560 100644
> > ---
> a/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
> > +++
> b/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
> > @@ -183,7 +183,7 @@ public class TestAbandonedObjectPool {
> >           }
> >
> >           @Override
> > -        public void destroyObject(final PooledObject<PooledTestObject>
> obj, final DestroyMode mode) throws Exception {
> > +        public void destroyObject(final PooledObject<PooledTestObject>
> obj, final DestroyMode destroyMode) throws Exception {
> >               obj.getObject().setActive(false);
> >               // while destroying instances, yield control to other
> threads
> >               // helps simulate threading errors
> > @@ -191,7 +191,7 @@ public class TestAbandonedObjectPool {
> >               if (destroyLatency != 0) {
> >                   Thread.sleep(destroyLatency);
> >               }
> > -            obj.getObject().destroy(mode);
> > +            obj.getObject().destroy(destroyMode);
> >           }
> >
> >           @Override
> > diff --git
> a/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> b/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> > index 39e898c..cd36876 100644
> > ---
> a/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> > +++
> b/src/test/java/org/apache/commons/pool2/impl/TestGenericKeyedObjectPool.java
> > @@ -20,6 +20,7 @@ package org.apache.commons.pool2.impl;
> >
> >   import static org.junit.jupiter.api.Assertions.assertEquals;
> >   import static org.junit.jupiter.api.Assertions.assertFalse;
> > +import static org.junit.jupiter.api.Assertions.assertNotEquals;
> >   import static org.junit.jupiter.api.Assertions.assertNotNull;
> >   import static org.junit.jupiter.api.Assertions.assertNotSame;
> >   import static org.junit.jupiter.api.Assertions.assertSame;
> > @@ -906,6 +907,18 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >       }
> >
> >       @Test
> > +    public void testAppendStats() {
> > +        assertFalse(gkoPool.getMessageStatistics());
> > +        assertEquals("foo", (gkoPool.appendStats("foo")));
> > +        try (final GenericKeyedObjectPool<?, ?> pool = new
> GenericKeyedObjectPool<>(new SimpleFactory<>())) {
> > +            pool.setMessagesStatistics(true);
> > +            assertNotEquals("foo", (pool.appendStats("foo")));
> > +            pool.setMessagesStatistics(false);
> > +            assertEquals("foo", (pool.appendStats("foo")));
> > +        }
> > +    }
> > +
> > +    @Test
> >       @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> >       public void testBlockedKeyDoesNotBlockPool() throws Exception {
> >           gkoPool.setBlockWhenExhausted(true);
> > @@ -1025,6 +1038,7 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >           gkoPool.close();
> >       }
> >
> > +
> >       /**
> >        * Test to make sure that clearOldest does not destroy instances
> that have been checked out.
> >        *
> > @@ -1061,7 +1075,6 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >           }
> >       }
> >
> > -
> >       // POOL-259
> >       @Test
> >       public void testClientWaitStats() throws Exception {
> > @@ -1483,6 +1496,27 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >
> >       @Test
> >       @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> > +    public void testExceptionInValidationDuringEviction() throws
> Exception {
> > +        gkoPool.setMaxIdlePerKey(1);
> > +        gkoPool.setMinEvictableIdleTime(Duration.ZERO);
> > +        gkoPool.setTestWhileIdle(true);
> > +
> > +        final String obj = gkoPool.borrowObject("one");
> > +        gkoPool.returnObject("one", obj);
> > +
> > +        simpleFactory.setThrowExceptionOnValidate(true);
> > +        try {
> > +            gkoPool.evict();
> > +            fail("Expecting RuntimeException");
> > +        } catch (final RuntimeException e) {
> > +            // expected
> > +        }
> > +        assertEquals(0, gkoPool.getNumActive());
> > +        assertEquals(0, gkoPool.getNumIdle());
> > +    }
> > +
> > +    @Test
> > +    @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> >       public void testExceptionOnActivateDuringBorrow() throws Exception
> {
> >           final String obj1 = gkoPool.borrowObject("one");
> >           final String obj2 = gkoPool.borrowObject("one");
> > @@ -1514,6 +1548,7 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >           assertEquals(0, gkoPool.getNumIdle());
> >       }
> >
> > +
> >       @Test
> >       @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> >       public void testExceptionOnDestroyDuringBorrow() throws Exception {
> > @@ -1550,7 +1585,6 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >           assertEquals(0, gkoPool.getNumIdle());
> >       }
> >
> > -
> >       @Test
> >       @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> >       public void testExceptionOnPassivateDuringReturn() throws
> Exception {
> > @@ -1563,27 +1597,6 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >
> >       @Test
> >       @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> > -    public void testExceptionInValidationDuringEviction() throws
> Exception {
> > -        gkoPool.setMaxIdlePerKey(1);
> > -        gkoPool.setMinEvictableIdleTime(Duration.ZERO);
> > -        gkoPool.setTestWhileIdle(true);
> > -
> > -        final String obj = gkoPool.borrowObject("one");
> > -        gkoPool.returnObject("one", obj);
> > -
> > -        simpleFactory.setThrowExceptionOnValidate(true);
> > -        try {
> > -            gkoPool.evict();
> > -            fail("Expecting RuntimeException");
> > -        } catch (final RuntimeException e) {
> > -            // expected
> > -        }
> > -        assertEquals(0, gkoPool.getNumActive());
> > -        assertEquals(0, gkoPool.getNumIdle());
> > -    }
> > -
> > -    @Test
> > -    @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
> >       public void testFIFO() throws Exception {
> >           gkoPool.setLifo(false);
> >           final String key = "key";
> > @@ -1600,6 +1613,11 @@ public class TestGenericKeyedObjectPool extends
> TestKeyedObjectPool {
> >           assertEquals( "key4", gkoPool.borrowObject(key),"new-4");
> >       }
> >
> > +    @Test
> > +    public void testGetStatsString() {
> > +        assertNotNull((gkoPool.getStatsString()));
> > +    }
> > +
> >       /**
> >        * Verify that threads waiting on a depleted pool get served when
> a checked out object is
> >        * invalidated.
> > diff --git
> a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> > index 1014588..fe646a3 100644
> > ---
> a/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> > +++
> b/src/test/java/org/apache/commons/pool2/impl/TestGenericObjectPool.java
> > @@ -20,6 +20,7 @@ package org.apache.commons.pool2.impl;
> >
> >   import static org.junit.jupiter.api.Assertions.assertEquals;
> >   import static org.junit.jupiter.api.Assertions.assertFalse;
> > +import static org.junit.jupiter.api.Assertions.assertNotEquals;
> >   import static org.junit.jupiter.api.Assertions.assertNotNull;
> >   import static org.junit.jupiter.api.Assertions.assertNull;
> >   import static org.junit.jupiter.api.Assertions.assertThrows;
> > @@ -58,6 +59,7 @@ import org.apache.commons.pool2.VisitTracker;
> >   import org.apache.commons.pool2.VisitTrackerFactory;
> >   import org.apache.commons.pool2.Waiter;
> >   import org.apache.commons.pool2.WaiterFactory;
> > +import
> org.apache.commons.pool2.impl.TestGenericKeyedObjectPool.SimpleFactory;
> >   import org.junit.jupiter.api.AfterEach;
> >   import org.junit.jupiter.api.BeforeEach;
> >   import org.junit.jupiter.api.Test;
> > @@ -83,7 +85,9 @@ public class TestGenericObjectPool extends
> TestBaseObjectPool {
> >                   } else {
> >                       genericObjectPool.evict();
> >                   }
> > -            } catch (final Exception e) { /* Ignore */}
> > +            } catch (final Exception e) {
> > +                // Ignore.
> > +            }
> >           }
> >       }
> >
> > @@ -999,6 +1003,18 @@ public class TestGenericObjectPool extends
> TestBaseObjectPool {
> >           assertEquals( 0, genericObjectPool.getNumActive(),"should be
> zero active");
> >       }
> >
> > +    @Test
> > +    public void testAppendStats() {
> > +        assertFalse(genericObjectPool.getMessageStatistics());
> > +        assertEquals("foo", (genericObjectPool.appendStats("foo")));
> > +        try (final GenericObjectPool<?> pool = new
> GenericObjectPool<>(new SimpleFactory())) {
> > +            pool.setMessagesStatistics(true);
> > +            assertNotEquals("foo", (pool.appendStats("foo")));
> > +            pool.setMessagesStatistics(false);
> > +            assertEquals("foo", (pool.appendStats("foo")));
> > +        }
> > +    }
> > +
> >       /*
> >        * Note: This test relies on timing for correct execution. There
> *should* be
> >        * enough margin for this to work correctly on most (all?) systems
> but be
> > @@ -1185,6 +1201,7 @@ public class TestGenericObjectPool extends
> TestBaseObjectPool {
> >           }
> >       }
> >
> > +
> >       /**
> >        * POOL-231 - verify that concurrent invalidates of the same
> object do not
> >        * corrupt pool destroyCount.
> > @@ -1238,7 +1255,6 @@ public class TestGenericObjectPool extends
> TestBaseObjectPool {
> >           assertEquals(nIterations,
> genericObjectPool.getDestroyedCount());
> >       }
> >
> > -
> >       @Test
> >       public void testConstructorNullFactory() {
> >           // add dummy assert (won't be invoked because of IAE) to avoid
> "unused" warning
> > @@ -1916,6 +1932,14 @@ public class TestGenericObjectPool extends
> TestBaseObjectPool {
> >           }
> >       }
> >
> > +    @Test
> > +    public void testGetStatsString() {
> > +        try (final GenericObjectPool<String> pool = new
> GenericObjectPool<>(
> > +                new
> TestSynchronizedPooledObjectFactory<>(createNullPooledObjectFactory()))) {
> > +            assertNotNull(pool.getStatsString());
> > +        }
> > +    }
> > +
> >       /**
> >        * Verify that threads waiting on a depleted pool get served when
> a checked out object is
> >        * invalidated.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
> For additional commands, e-mail: dev-h...@commons.apache.org
>
>

Reply via email to