001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.pool2.impl;
018
019import java.io.PrintWriter;
020import java.io.StringWriter;
021import java.io.Writer;
022import java.lang.management.ManagementFactory;
023import java.lang.ref.WeakReference;
024import java.lang.reflect.InvocationTargetException;
025import java.util.Arrays;
026import java.util.Deque;
027import java.util.Iterator;
028import java.util.TimerTask;
029import java.util.concurrent.ScheduledFuture;
030import java.util.concurrent.TimeUnit;
031import java.util.concurrent.atomic.AtomicLong;
032
033import javax.management.InstanceAlreadyExistsException;
034import javax.management.InstanceNotFoundException;
035import javax.management.MBeanRegistrationException;
036import javax.management.MBeanServer;
037import javax.management.MalformedObjectNameException;
038import javax.management.NotCompliantMBeanException;
039import javax.management.ObjectName;
040
041import org.apache.commons.pool2.BaseObject;
042import org.apache.commons.pool2.PooledObject;
043import org.apache.commons.pool2.PooledObjectState;
044import org.apache.commons.pool2.SwallowedExceptionListener;
045
046/**
047 * Base class that provides common functionality for {@link GenericObjectPool}
048 * and {@link GenericKeyedObjectPool}. The primary reason this class exists is
049 * reduce code duplication between the two pool implementations.
050 *
051 * @param <T> Type of element pooled in this pool.
052 *
053 * This class is intended to be thread-safe.
054 *
055 * @since 2.0
056 */
057public abstract class BaseGenericObjectPool<T> extends BaseObject {
058
059    // Constants
060    /**
061     * The size of the caches used to store historical data for some attributes
062     * so that rolling means may be calculated.
063     */
064    public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100;
065
066    private static final String EVICTION_POLICY_TYPE_NAME = EvictionPolicy.class.getName();
067
068    // Configuration attributes
069    private volatile int maxTotal =
070            GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
071    private volatile boolean blockWhenExhausted =
072            BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
073    private volatile long maxWaitMillis =
074            BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
075    private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
076    private final boolean fairness;
077    private volatile boolean testOnCreate =
078            BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
079    private volatile boolean testOnBorrow =
080            BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
081    private volatile boolean testOnReturn =
082            BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
083    private volatile boolean testWhileIdle =
084            BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
085    private volatile long timeBetweenEvictionRunsMillis =
086            BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
087    private volatile int numTestsPerEvictionRun =
088            BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
089    private volatile long minEvictableIdleTimeMillis =
090            BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
091    private volatile long softMinEvictableIdleTimeMillis =
092            BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
093    private volatile EvictionPolicy<T> evictionPolicy;
094    private volatile long evictorShutdownTimeoutMillis =
095            BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
096
097
098    // Internal (primarily state) attributes
099    final Object closeLock = new Object();
100    volatile boolean closed = false;
101    final Object evictionLock = new Object();
102    private Evictor evictor = null; // @GuardedBy("evictionLock")
103    EvictionIterator evictionIterator = null; // @GuardedBy("evictionLock")
104    /*
105     * Class loader for evictor thread to use since, in a JavaEE or similar
106     * environment, the context class loader for the evictor thread may not have
107     * visibility of the correct factory. See POOL-161. Uses a weak reference to
108     * avoid potential memory leaks if the Pool is discarded rather than closed.
109     */
110    private final WeakReference<ClassLoader> factoryClassLoader;
111
112
113    // Monitoring (primarily JMX) attributes
114    private final ObjectName objectName;
115    private final String creationStackTrace;
116    private final AtomicLong borrowedCount = new AtomicLong(0);
117    private final AtomicLong returnedCount = new AtomicLong(0);
118    final AtomicLong createdCount = new AtomicLong(0);
119    final AtomicLong destroyedCount = new AtomicLong(0);
120    final AtomicLong destroyedByEvictorCount = new AtomicLong(0);
121    final AtomicLong destroyedByBorrowValidationCount = new AtomicLong(0);
122    private final StatsStore activeTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
123    private final StatsStore idleTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
124    private final StatsStore waitTimes = new StatsStore(MEAN_TIMING_STATS_CACHE_SIZE);
125    private final AtomicLong maxBorrowWaitTimeMillis = new AtomicLong(0L);
126    private volatile SwallowedExceptionListener swallowedExceptionListener = null;
127
128
129    /**
130     * Handles JMX registration (if required) and the initialization required for
131     * monitoring.
132     *
133     * @param config        Pool configuration
134     * @param jmxNameBase   The default base JMX name for the new pool unless
135     *                      overridden by the config
136     * @param jmxNamePrefix Prefix to be used for JMX name for the new pool
137     */
138    public BaseGenericObjectPool(final BaseObjectPoolConfig<T> config,
139            final String jmxNameBase, final String jmxNamePrefix) {
140        if (config.getJmxEnabled()) {
141            this.objectName = jmxRegister(config, jmxNameBase, jmxNamePrefix);
142        } else {
143            this.objectName = null;
144        }
145
146        // Populate the creation stack trace
147        this.creationStackTrace = getStackTrace(new Exception());
148
149        // save the current TCCL (if any) to be used later by the evictor Thread
150        final ClassLoader cl = Thread.currentThread().getContextClassLoader();
151        if (cl == null) {
152            factoryClassLoader = null;
153        } else {
154            factoryClassLoader = new WeakReference<>(cl);
155        }
156
157        fairness = config.getFairness();
158    }
159
160
161    /**
162     * Returns the maximum number of objects that can be allocated by the pool
163     * (checked out to clients, or idle awaiting checkout) at a given time. When
164     * negative, there is no limit to the number of objects that can be
165     * managed by the pool at one time.
166     *
167     * @return the cap on the total number of object instances managed by the
168     *         pool.
169     *
170     * @see #setMaxTotal
171     */
172    public final int getMaxTotal() {
173        return maxTotal;
174    }
175
176    /**
177     * Sets the cap on the number of objects that can be allocated by the pool
178     * (checked out to clients, or idle awaiting checkout) at a given time. Use
179     * a negative value for no limit.
180     *
181     * @param maxTotal  The cap on the total number of object instances managed
182     *                  by the pool. Negative values mean that there is no limit
183     *                  to the number of objects allocated by the pool.
184     *
185     * @see #getMaxTotal
186     */
187    public final void setMaxTotal(final int maxTotal) {
188        this.maxTotal = maxTotal;
189    }
190
191    /**
192     * Returns whether to block when the <code>borrowObject()</code> method is
193     * invoked when the pool is exhausted (the maximum number of "active"
194     * objects has been reached).
195     *
196     * @return <code>true</code> if <code>borrowObject()</code> should block
197     *         when the pool is exhausted
198     *
199     * @see #setBlockWhenExhausted
200     */
201    public final boolean getBlockWhenExhausted() {
202        return blockWhenExhausted;
203    }
204
205    /**
206     * Sets whether to block when the <code>borrowObject()</code> method is
207     * invoked when the pool is exhausted (the maximum number of "active"
208     * objects has been reached).
209     *
210     * @param blockWhenExhausted    <code>true</code> if
211     *                              <code>borrowObject()</code> should block
212     *                              when the pool is exhausted
213     *
214     * @see #getBlockWhenExhausted
215     */
216    public final void setBlockWhenExhausted(final boolean blockWhenExhausted) {
217        this.blockWhenExhausted = blockWhenExhausted;
218    }
219
220    /**
221     * Returns the maximum amount of time (in milliseconds) the
222     * <code>borrowObject()</code> method should block before throwing an
223     * exception when the pool is exhausted and
224     * {@link #getBlockWhenExhausted} is true. When less than 0, the
225     * <code>borrowObject()</code> method may block indefinitely.
226     *
227     * @return the maximum number of milliseconds <code>borrowObject()</code>
228     *         will block.
229     *
230     * @see #setMaxWaitMillis
231     * @see #setBlockWhenExhausted
232     */
233    public final long getMaxWaitMillis() {
234        return maxWaitMillis;
235    }
236
237    /**
238     * Sets the maximum amount of time (in milliseconds) the
239     * <code>borrowObject()</code> method should block before throwing an
240     * exception when the pool is exhausted and
241     * {@link #getBlockWhenExhausted} is true. When less than 0, the
242     * <code>borrowObject()</code> method may block indefinitely.
243     *
244     * @param maxWaitMillis the maximum number of milliseconds
245     *                      <code>borrowObject()</code> will block or negative
246     *                      for indefinitely.
247     *
248     * @see #getMaxWaitMillis
249     * @see #setBlockWhenExhausted
250     */
251    public final void setMaxWaitMillis(final long maxWaitMillis) {
252        this.maxWaitMillis = maxWaitMillis;
253    }
254
255    /**
256     * Returns whether the pool has LIFO (last in, first out) behaviour with
257     * respect to idle objects - always returning the most recently used object
258     * from the pool, or as a FIFO (first in, first out) queue, where the pool
259     * always returns the oldest object in the idle object pool.
260     *
261     * @return <code>true</code> if the pool is configured with LIFO behaviour
262     *         or <code>false</code> if the pool is configured with FIFO
263     *         behaviour
264     *
265     * @see #setLifo
266     */
267    public final boolean getLifo() {
268        return lifo;
269    }
270
271    /**
272     * Returns whether or not the pool serves threads waiting to borrow objects fairly.
273     * True means that waiting threads are served as if waiting in a FIFO queue.
274     *
275     * @return <code>true</code> if waiting threads are to be served
276     *             by the pool in arrival order
277     */
278    public final boolean getFairness() {
279        return fairness;
280    }
281
282    /**
283     * Sets whether the pool has LIFO (last in, first out) behaviour with
284     * respect to idle objects - always returning the most recently used object
285     * from the pool, or as a FIFO (first in, first out) queue, where the pool
286     * always returns the oldest object in the idle object pool.
287     *
288     * @param lifo  <code>true</code> if the pool is to be configured with LIFO
289     *              behaviour or <code>false</code> if the pool is to be
290     *              configured with FIFO behaviour
291     *
292     * @see #getLifo()
293     */
294    public final void setLifo(final boolean lifo) {
295        this.lifo = lifo;
296    }
297
298    /**
299     * Returns whether objects created for the pool will be validated before
300     * being returned from the <code>borrowObject()</code> method. Validation is
301     * performed by the <code>validateObject()</code> method of the factory
302     * associated with the pool. If the object fails to validate, then
303     * <code>borrowObject()</code> will fail.
304     *
305     * @return <code>true</code> if newly created objects are validated before
306     *         being returned from the <code>borrowObject()</code> method
307     *
308     * @see #setTestOnCreate
309     *
310     * @since 2.2
311     */
312    public final boolean getTestOnCreate() {
313        return testOnCreate;
314    }
315
316    /**
317     * Sets whether objects created for the pool will be validated before
318     * being returned from the <code>borrowObject()</code> method. Validation is
319     * performed by the <code>validateObject()</code> method of the factory
320     * associated with the pool. If the object fails to validate, then
321     * <code>borrowObject()</code> will fail.
322     *
323     * @param testOnCreate  <code>true</code> if newly created objects should be
324     *                      validated before being returned from the
325     *                      <code>borrowObject()</code> method
326     *
327     * @see #getTestOnCreate
328     *
329     * @since 2.2
330     */
331    public final void setTestOnCreate(final boolean testOnCreate) {
332        this.testOnCreate = testOnCreate;
333    }
334
335    /**
336     * Returns whether objects borrowed from the pool will be validated before
337     * being returned from the <code>borrowObject()</code> method. Validation is
338     * performed by the <code>validateObject()</code> method of the factory
339     * associated with the pool. If the object fails to validate, it will be
340     * removed from the pool and destroyed, and a new attempt will be made to
341     * borrow an object from the pool.
342     *
343     * @return <code>true</code> if objects are validated before being returned
344     *         from the <code>borrowObject()</code> method
345     *
346     * @see #setTestOnBorrow
347     */
348    public final boolean getTestOnBorrow() {
349        return testOnBorrow;
350    }
351
352    /**
353     * Sets whether objects borrowed from the pool will be validated before
354     * being returned from the <code>borrowObject()</code> method. Validation is
355     * performed by the <code>validateObject()</code> method of the factory
356     * associated with the pool. If the object fails to validate, it will be
357     * removed from the pool and destroyed, and a new attempt will be made to
358     * borrow an object from the pool.
359     *
360     * @param testOnBorrow  <code>true</code> if objects should be validated
361     *                      before being returned from the
362     *                      <code>borrowObject()</code> method
363     *
364     * @see #getTestOnBorrow
365     */
366    public final void setTestOnBorrow(final boolean testOnBorrow) {
367        this.testOnBorrow = testOnBorrow;
368    }
369
370    /**
371     * Returns whether objects borrowed from the pool will be validated when
372     * they are returned to the pool via the <code>returnObject()</code> method.
373     * Validation is performed by the <code>validateObject()</code> method of
374     * the factory associated with the pool. Returning objects that fail validation
375     * are destroyed rather then being returned the pool.
376     *
377     * @return <code>true</code> if objects are validated on return to
378     *         the pool via the <code>returnObject()</code> method
379     *
380     * @see #setTestOnReturn
381     */
382    public final boolean getTestOnReturn() {
383        return testOnReturn;
384    }
385
386    /**
387     * Sets whether objects borrowed from the pool will be validated when
388     * they are returned to the pool via the <code>returnObject()</code> method.
389     * Validation is performed by the <code>validateObject()</code> method of
390     * the factory associated with the pool. Returning objects that fail validation
391     * are destroyed rather then being returned the pool.
392     *
393     * @param testOnReturn <code>true</code> if objects are validated on
394     *                     return to the pool via the
395     *                     <code>returnObject()</code> method
396     *
397     * @see #getTestOnReturn
398     */
399    public final void setTestOnReturn(final boolean testOnReturn) {
400        this.testOnReturn = testOnReturn;
401    }
402
403    /**
404     * Returns whether objects sitting idle in the pool will be validated by the
405     * idle object evictor (if any - see
406     * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
407     * by the <code>validateObject()</code> method of the factory associated
408     * with the pool. If the object fails to validate, it will be removed from
409     * the pool and destroyed.
410     *
411     * @return <code>true</code> if objects will be validated by the evictor
412     *
413     * @see #setTestWhileIdle
414     * @see #setTimeBetweenEvictionRunsMillis
415     */
416    public final boolean getTestWhileIdle() {
417        return testWhileIdle;
418    }
419
420    /**
421     * Returns whether objects sitting idle in the pool will be validated by the
422     * idle object evictor (if any - see
423     * {@link #setTimeBetweenEvictionRunsMillis(long)}). Validation is performed
424     * by the <code>validateObject()</code> method of the factory associated
425     * with the pool. If the object fails to validate, it will be removed from
426     * the pool and destroyed.  Note that setting this property has no effect
427     * unless the idle object evictor is enabled by setting
428     * <code>timeBetweenEvictionRunsMillis</code> to a positive value.
429     *
430     * @param testWhileIdle
431     *            <code>true</code> so objects will be validated by the evictor
432     *
433     * @see #getTestWhileIdle
434     * @see #setTimeBetweenEvictionRunsMillis
435     */
436    public final void setTestWhileIdle(final boolean testWhileIdle) {
437        this.testWhileIdle = testWhileIdle;
438    }
439
440    /**
441     * Returns the number of milliseconds to sleep between runs of the idle
442     * object evictor thread. When non-positive, no idle object evictor thread
443     * will be run.
444     *
445     * @return number of milliseconds to sleep between evictor runs
446     *
447     * @see #setTimeBetweenEvictionRunsMillis
448     */
449    public final long getTimeBetweenEvictionRunsMillis() {
450        return timeBetweenEvictionRunsMillis;
451    }
452
453    /**
454     * Sets the number of milliseconds to sleep between runs of the idle object evictor thread.
455     * <ul>
456     * <li>When positive, the idle object evictor thread starts.</li>
457     * <li>When non-positive, no idle object evictor thread runs.</li>
458     * </ul>
459     *
460     * @param timeBetweenEvictionRunsMillis
461     *            number of milliseconds to sleep between evictor runs
462     *
463     * @see #getTimeBetweenEvictionRunsMillis
464     */
465    public final void setTimeBetweenEvictionRunsMillis(
466            final long timeBetweenEvictionRunsMillis) {
467        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
468        startEvictor(timeBetweenEvictionRunsMillis);
469    }
470
471    /**
472     * Returns the maximum number of objects to examine during each run (if any)
473     * of the idle object evictor thread. When positive, the number of tests
474     * performed for a run will be the minimum of the configured value and the
475     * number of idle instances in the pool. When negative, the number of tests
476     * performed will be <code>ceil({@link #getNumIdle}/
477     * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
478     * value is <code>-n</code> roughly one nth of the idle objects will be
479     * tested per run.
480     *
481     * @return max number of objects to examine during each evictor run
482     *
483     * @see #setNumTestsPerEvictionRun
484     * @see #setTimeBetweenEvictionRunsMillis
485     */
486    public final int getNumTestsPerEvictionRun() {
487        return numTestsPerEvictionRun;
488    }
489
490    /**
491     * Sets the maximum number of objects to examine during each run (if any)
492     * of the idle object evictor thread. When positive, the number of tests
493     * performed for a run will be the minimum of the configured value and the
494     * number of idle instances in the pool. When negative, the number of tests
495     * performed will be <code>ceil({@link #getNumIdle}/
496     * abs({@link #getNumTestsPerEvictionRun}))</code> which means that when the
497     * value is <code>-n</code> roughly one nth of the idle objects will be
498     * tested per run.
499     *
500     * @param numTestsPerEvictionRun
501     *            max number of objects to examine during each evictor run
502     *
503     * @see #getNumTestsPerEvictionRun
504     * @see #setTimeBetweenEvictionRunsMillis
505     */
506    public final void setNumTestsPerEvictionRun(final int numTestsPerEvictionRun) {
507        this.numTestsPerEvictionRun = numTestsPerEvictionRun;
508    }
509
510    /**
511     * Returns the minimum amount of time an object may sit idle in the pool
512     * before it is eligible for eviction by the idle object evictor (if any -
513     * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
514     * no objects will be evicted from the pool due to idle time alone.
515     *
516     * @return minimum amount of time an object may sit idle in the pool before
517     *         it is eligible for eviction
518     *
519     * @see #setMinEvictableIdleTimeMillis
520     * @see #setTimeBetweenEvictionRunsMillis
521     */
522    public final long getMinEvictableIdleTimeMillis() {
523        return minEvictableIdleTimeMillis;
524    }
525
526    /**
527     * Sets the minimum amount of time an object may sit idle in the pool
528     * before it is eligible for eviction by the idle object evictor (if any -
529     * see {@link #setTimeBetweenEvictionRunsMillis(long)}). When non-positive,
530     * no objects will be evicted from the pool due to idle time alone.
531     *
532     * @param minEvictableIdleTimeMillis
533     *            minimum amount of time an object may sit idle in the pool
534     *            before it is eligible for eviction
535     *
536     * @see #getMinEvictableIdleTimeMillis
537     * @see #setTimeBetweenEvictionRunsMillis
538     */
539    public final void setMinEvictableIdleTimeMillis(
540            final long minEvictableIdleTimeMillis) {
541        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
542    }
543
544    /**
545     * Returns the minimum amount of time an object may sit idle in the pool
546     * before it is eligible for eviction by the idle object evictor (if any -
547     * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
548     * with the extra condition that at least <code>minIdle</code> object
549     * instances remain in the pool. This setting is overridden by
550     * {@link #getMinEvictableIdleTimeMillis} (that is, if
551     * {@link #getMinEvictableIdleTimeMillis} is positive, then
552     * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
553     *
554     * @return minimum amount of time an object may sit idle in the pool before
555     *         it is eligible for eviction if minIdle instances are available
556     *
557     * @see #setSoftMinEvictableIdleTimeMillis
558     */
559    public final long getSoftMinEvictableIdleTimeMillis() {
560        return softMinEvictableIdleTimeMillis;
561    }
562
563    /**
564     * Sets the minimum amount of time an object may sit idle in the pool
565     * before it is eligible for eviction by the idle object evictor (if any -
566     * see {@link #setTimeBetweenEvictionRunsMillis(long)}),
567     * with the extra condition that at least <code>minIdle</code> object
568     * instances remain in the pool. This setting is overridden by
569     * {@link #getMinEvictableIdleTimeMillis} (that is, if
570     * {@link #getMinEvictableIdleTimeMillis} is positive, then
571     * {@link #getSoftMinEvictableIdleTimeMillis} is ignored).
572     *
573     * @param softMinEvictableIdleTimeMillis
574     *            minimum amount of time an object may sit idle in the pool
575     *            before it is eligible for eviction if minIdle instances are
576     *            available
577     *
578     * @see #getSoftMinEvictableIdleTimeMillis
579     */
580    public final void setSoftMinEvictableIdleTimeMillis(
581            final long softMinEvictableIdleTimeMillis) {
582        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;
583    }
584
585    /**
586     * Returns the name of the {@link EvictionPolicy} implementation that is
587     * used by this pool.
588     *
589     * @return  The fully qualified class name of the {@link EvictionPolicy}
590     *
591     * @see #setEvictionPolicyClassName(String)
592     */
593    public final String getEvictionPolicyClassName() {
594        return evictionPolicy.getClass().getName();
595    }
596
597    /**
598     * Sets the eviction policy for this pool.
599     *
600     * @param evictionPolicy
601     *            the eviction policy for this pool.
602     * @since 2.6.0
603     */
604    public void setEvictionPolicy(final EvictionPolicy<T> evictionPolicy) {
605        this.evictionPolicy = evictionPolicy;
606    }
607
608    /**
609     * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
610     * load the class using the given class loader. If that fails, use the class loader for the {@link EvictionPolicy}
611     * interface.
612     *
613     * @param evictionPolicyClassName
614     *            the fully qualified class name of the new eviction policy
615     * @param classLoader
616     *            the class loader to load the given {@code evictionPolicyClassName}.
617     *
618     * @see #getEvictionPolicyClassName()
619     * @since 2.6.0 If loading the class using the given class loader fails, use the class loader for the
620     *        {@link EvictionPolicy} interface.
621     */
622    public final void setEvictionPolicyClassName(final String evictionPolicyClassName, final ClassLoader classLoader) {
623        // Getting epClass here and now best matches the caller's environment
624        final Class<?> epClass = EvictionPolicy.class;
625        final ClassLoader epClassLoader = epClass.getClassLoader();
626        try {
627            try {
628                setEvictionPolicy(evictionPolicyClassName, classLoader);
629            } catch (final ClassCastException | ClassNotFoundException e) {
630                setEvictionPolicy(evictionPolicyClassName, epClassLoader);
631            }
632        } catch (final ClassCastException e) {
633            throw new IllegalArgumentException("Class " + evictionPolicyClassName + " from class loaders ["
634                    + classLoader + ", " + epClassLoader + "] do not implement " + EVICTION_POLICY_TYPE_NAME);
635        } catch (final ClassNotFoundException | InstantiationException | IllegalAccessException
636                | InvocationTargetException | NoSuchMethodException e) {
637            final String exMessage = "Unable to create " + EVICTION_POLICY_TYPE_NAME + " instance of type "
638                    + evictionPolicyClassName;
639            throw new IllegalArgumentException(exMessage, e);
640        }
641    }
642
643    @SuppressWarnings("unchecked")
644    private void setEvictionPolicy(final String className, final ClassLoader classLoader)
645            throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
646        final Class<?> clazz = Class.forName(className, true, classLoader);
647        final Object policy = clazz.getConstructor().newInstance();
648        this.evictionPolicy = (EvictionPolicy<T>) policy;
649    }
650
651    /**
652     * Sets the name of the {@link EvictionPolicy} implementation that is used by this pool. The Pool will attempt to
653     * load the class using the thread context class loader. If that fails, the use the class loader for the
654     * {@link EvictionPolicy} interface.
655     *
656     * @param evictionPolicyClassName
657     *            the fully qualified class name of the new eviction policy
658     *
659     * @see #getEvictionPolicyClassName()
660     * @since 2.6.0 If loading the class using the thread context class loader fails, use the class loader for the
661     *        {@link EvictionPolicy} interface.
662     */
663    public final void setEvictionPolicyClassName(final String evictionPolicyClassName) {
664        setEvictionPolicyClassName(evictionPolicyClassName, Thread.currentThread().getContextClassLoader());
665    }
666
667    /**
668     * Gets the timeout that will be used when waiting for the Evictor to
669     * shutdown if this pool is closed and it is the only pool still using the
670     * the value for the Evictor.
671     *
672     * @return  The timeout in milliseconds that will be used while waiting for
673     *          the Evictor to shut down.
674     */
675    public final long getEvictorShutdownTimeoutMillis() {
676        return evictorShutdownTimeoutMillis;
677    }
678
679    /**
680     * Sets the timeout that will be used when waiting for the Evictor to
681     * shutdown if this pool is closed and it is the only pool still using the
682     * the value for the Evictor.
683     *
684     * @param evictorShutdownTimeoutMillis  the timeout in milliseconds that
685     *                                      will be used while waiting for the
686     *                                      Evictor to shut down.
687     */
688    public final void setEvictorShutdownTimeoutMillis(
689            final long evictorShutdownTimeoutMillis) {
690        this.evictorShutdownTimeoutMillis = evictorShutdownTimeoutMillis;
691    }
692
693    /**
694     * Closes the pool, destroys the remaining idle objects and, if registered
695     * in JMX, deregisters it.
696     */
697    public abstract void close();
698
699    /**
700     * Has this pool instance been closed.
701     * @return <code>true</code> when this pool has been closed.
702     */
703    public final boolean isClosed() {
704        return closed;
705    }
706
707    /**
708     * <p>Perform <code>numTests</code> idle object eviction tests, evicting
709     * examined objects that meet the criteria for eviction. If
710     * <code>testWhileIdle</code> is true, examined objects are validated
711     * when visited (and removed if invalid); otherwise only objects that
712     * have been idle for more than <code>minEvicableIdleTimeMillis</code>
713     * are removed.</p>
714     *
715     * @throws Exception when there is a problem evicting idle objects.
716     */
717    public abstract void evict() throws Exception;
718
719    /**
720     * Returns the {@link EvictionPolicy} defined for this pool.
721     *
722     * @return the eviction policy
723     * @since 2.4
724     * @since 2.6.0 Changed access from protected to public.
725     */
726    public EvictionPolicy<T> getEvictionPolicy() {
727        return evictionPolicy;
728    }
729
730    /**
731     * Verifies that the pool is open.
732     * @throws IllegalStateException if the pool is closed.
733     */
734    final void assertOpen() throws IllegalStateException {
735        if (isClosed()) {
736            throw new IllegalStateException("Pool not open");
737        }
738    }
739
740    /**
741     * <p>Starts the evictor with the given delay. If there is an evictor
742     * running when this method is called, it is stopped and replaced with a
743     * new evictor with the specified delay.</p>
744     *
745     * <p>This method needs to be final, since it is called from a constructor.
746     * See POOL-195.</p>
747     *
748     * @param delay time in milliseconds before start and between eviction runs
749     */
750    final void startEvictor(final long delay) {
751        synchronized (evictionLock) {
752            if (null != evictor) {
753                EvictionTimer.cancel(evictor, evictorShutdownTimeoutMillis, TimeUnit.MILLISECONDS);
754                evictor = null;
755                evictionIterator = null;
756            }
757            if (delay > 0) {
758                evictor = new Evictor();
759                EvictionTimer.schedule(evictor, delay, delay);
760            }
761        }
762    }
763
764    /**
765     * Tries to ensure that the configured minimum number of idle instances are
766     * available in the pool.
767     * @throws Exception if an error occurs creating idle instances
768     */
769    abstract void ensureMinIdle() throws Exception;
770
771
772    // Monitoring (primarily JMX) related methods
773
774    /**
775     * Provides the name under which the pool has been registered with the
776     * platform MBean server or <code>null</code> if the pool has not been
777     * registered.
778     * @return the JMX name
779     */
780    public final ObjectName getJmxName() {
781        return objectName;
782    }
783
784    /**
785     * Provides the stack trace for the call that created this pool. JMX
786     * registration may trigger a memory leak so it is important that pools are
787     * deregistered when no longer used by calling the {@link #close()} method.
788     * This method is provided to assist with identifying code that creates but
789     * does not close it thereby creating a memory leak.
790     * @return pool creation stack trace
791     */
792    public final String getCreationStackTrace() {
793        return creationStackTrace;
794    }
795
796    /**
797     * The total number of objects successfully borrowed from this pool over the
798     * lifetime of the pool.
799     * @return the borrowed object count
800     */
801    public final long getBorrowedCount() {
802        return borrowedCount.get();
803    }
804
805    /**
806     * The total number of objects returned to this pool over the lifetime of
807     * the pool. This excludes attempts to return the same object multiple
808     * times.
809     * @return the returned object count
810     */
811    public final long getReturnedCount() {
812        return returnedCount.get();
813    }
814
815    /**
816     * The total number of objects created for this pool over the lifetime of
817     * the pool.
818     * @return the created object count
819     */
820    public final long getCreatedCount() {
821        return createdCount.get();
822    }
823
824    /**
825     * The total number of objects destroyed by this pool over the lifetime of
826     * the pool.
827     * @return the destroyed object count
828     */
829    public final long getDestroyedCount() {
830        return destroyedCount.get();
831    }
832
833    /**
834     * The total number of objects destroyed by the evictor associated with this
835     * pool over the lifetime of the pool.
836     * @return the evictor destroyed object count
837     */
838    public final long getDestroyedByEvictorCount() {
839        return destroyedByEvictorCount.get();
840    }
841
842    /**
843     * The total number of objects destroyed by this pool as a result of failing
844     * validation during <code>borrowObject()</code> over the lifetime of the
845     * pool.
846     * @return validation destroyed object count
847     */
848    public final long getDestroyedByBorrowValidationCount() {
849        return destroyedByBorrowValidationCount.get();
850    }
851
852    /**
853     * The mean time objects are active for based on the last {@link
854     * #MEAN_TIMING_STATS_CACHE_SIZE} objects returned to the pool.
855     * @return mean time an object has been checked out from the pool among
856     * recently returned objects
857     */
858    public final long getMeanActiveTimeMillis() {
859        return activeTimes.getMean();
860    }
861
862    /**
863     * The mean time objects are idle for based on the last {@link
864     * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
865     * @return mean time an object has been idle in the pool among recently
866     * borrowed objects
867     */
868    public final long getMeanIdleTimeMillis() {
869        return idleTimes.getMean();
870    }
871
872    /**
873     * The mean time threads wait to borrow an object based on the last {@link
874     * #MEAN_TIMING_STATS_CACHE_SIZE} objects borrowed from the pool.
875     * @return mean time in milliseconds that a recently served thread has had
876     * to wait to borrow an object from the pool
877     */
878    public final long getMeanBorrowWaitTimeMillis() {
879        return waitTimes.getMean();
880    }
881
882    /**
883     * The maximum time a thread has waited to borrow objects from the pool.
884     * @return maximum wait time in milliseconds since the pool was created
885     */
886    public final long getMaxBorrowWaitTimeMillis() {
887        return maxBorrowWaitTimeMillis.get();
888    }
889
890    /**
891     * The number of instances currently idle in this pool.
892     * @return count of instances available for checkout from the pool
893     */
894    public abstract int getNumIdle();
895
896    /**
897     * The listener used (if any) to receive notifications of exceptions
898     * unavoidably swallowed by the pool.
899     *
900     * @return The listener or <code>null</code> for no listener
901     */
902    public final SwallowedExceptionListener getSwallowedExceptionListener() {
903        return swallowedExceptionListener;
904    }
905
906    /**
907     * The listener used (if any) to receive notifications of exceptions
908     * unavoidably swallowed by the pool.
909     *
910     * @param swallowedExceptionListener    The listener or <code>null</code>
911     *                                      for no listener
912     */
913    public final void setSwallowedExceptionListener(
914            final SwallowedExceptionListener swallowedExceptionListener) {
915        this.swallowedExceptionListener = swallowedExceptionListener;
916    }
917
918    /**
919     * Swallows an exception and notifies the configured listener for swallowed
920     * exceptions queue.
921     *
922     * @param swallowException exception to be swallowed
923     */
924    final void swallowException(final Exception swallowException) {
925        final SwallowedExceptionListener listener = getSwallowedExceptionListener();
926
927        if (listener == null) {
928            return;
929        }
930
931        try {
932            listener.onSwallowException(swallowException);
933        } catch (final VirtualMachineError e) {
934            throw e;
935        } catch (final Throwable t) {
936            // Ignore. Enjoy the irony.
937        }
938    }
939
940    /**
941     * Updates statistics after an object is borrowed from the pool.
942     * @param p object borrowed from the pool
943     * @param waitTime time (in milliseconds) that the borrowing thread had to wait
944     */
945    final void updateStatsBorrow(final PooledObject<T> p, final long waitTime) {
946        borrowedCount.incrementAndGet();
947        idleTimes.add(p.getIdleTimeMillis());
948        waitTimes.add(waitTime);
949
950        // lock-free optimistic-locking maximum
951        long currentMax;
952        do {
953            currentMax = maxBorrowWaitTimeMillis.get();
954            if (currentMax >= waitTime) {
955                break;
956            }
957        } while (!maxBorrowWaitTimeMillis.compareAndSet(currentMax, waitTime));
958    }
959
960    /**
961     * Updates statistics after an object is returned to the pool.
962     * @param activeTime the amount of time (in milliseconds) that the returning
963     * object was checked out
964     */
965    final void updateStatsReturn(final long activeTime) {
966        returnedCount.incrementAndGet();
967        activeTimes.add(activeTime);
968    }
969
970    /**
971     * Marks the object as returning to the pool.
972     * @param pooledObject instance to return to the keyed pool
973     */
974    protected void markReturningState(final PooledObject<T> pooledObject) {
975        synchronized(pooledObject) {
976            final PooledObjectState state = pooledObject.getState();
977            if (state != PooledObjectState.ALLOCATED) {
978                throw new IllegalStateException(
979                        "Object has already been returned to this pool or is invalid");
980            }
981            pooledObject.markReturning(); // Keep from being marked abandoned
982        }
983    }
984
985    /**
986     * Unregisters this pool's MBean.
987     */
988    final void jmxUnregister() {
989        if (objectName != null) {
990            try {
991                ManagementFactory.getPlatformMBeanServer().unregisterMBean(
992                        objectName);
993            } catch (final MBeanRegistrationException | InstanceNotFoundException e) {
994                swallowException(e);
995            }
996        }
997    }
998
999    /**
1000     * Registers the pool with the platform MBean server.
1001     * The registered name will be
1002     * <code>jmxNameBase + jmxNamePrefix + i</code> where i is the least
1003     * integer greater than or equal to 1 such that the name is not already
1004     * registered. Swallows MBeanRegistrationException, NotCompliantMBeanException
1005     * returning null.
1006     *
1007     * @param config Pool configuration
1008     * @param jmxNameBase default base JMX name for this pool
1009     * @param jmxNamePrefix name prefix
1010     * @return registered ObjectName, null if registration fails
1011     */
1012    private ObjectName jmxRegister(final BaseObjectPoolConfig<T> config,
1013            final String jmxNameBase, String jmxNamePrefix) {
1014        ObjectName newObjectName = null;
1015        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
1016        int i = 1;
1017        boolean registered = false;
1018        String base = config.getJmxNameBase();
1019        if (base == null) {
1020            base = jmxNameBase;
1021        }
1022        while (!registered) {
1023            try {
1024                ObjectName objName;
1025                // Skip the numeric suffix for the first pool in case there is
1026                // only one so the names are cleaner.
1027                if (i == 1) {
1028                    objName = new ObjectName(base + jmxNamePrefix);
1029                } else {
1030                    objName = new ObjectName(base + jmxNamePrefix + i);
1031                }
1032                mbs.registerMBean(this, objName);
1033                newObjectName = objName;
1034                registered = true;
1035            } catch (final MalformedObjectNameException e) {
1036                if (BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX.equals(
1037                        jmxNamePrefix) && jmxNameBase.equals(base)) {
1038                    // Shouldn't happen. Skip registration if it does.
1039                    registered = true;
1040                } else {
1041                    // Must be an invalid name. Use the defaults instead.
1042                    jmxNamePrefix =
1043                            BaseObjectPoolConfig.DEFAULT_JMX_NAME_PREFIX;
1044                    base = jmxNameBase;
1045                }
1046            } catch (final InstanceAlreadyExistsException e) {
1047                // Increment the index and try again
1048                i++;
1049            } catch (final MBeanRegistrationException | NotCompliantMBeanException e) {
1050                // Shouldn't happen. Skip registration if it does.
1051                registered = true;
1052            }
1053        }
1054        return newObjectName;
1055    }
1056
1057    /**
1058     * Gets the stack trace of an exception as a string.
1059     * @param e exception to trace
1060     * @return exception stack trace as a string
1061     */
1062    private String getStackTrace(final Exception e) {
1063        // Need the exception in string form to prevent the retention of
1064        // references to classes in the stack trace that could trigger a memory
1065        // leak in a container environment.
1066        final Writer w = new StringWriter();
1067        final PrintWriter pw = new PrintWriter(w);
1068        e.printStackTrace(pw);
1069        return w.toString();
1070    }
1071
1072    // Inner classes
1073
1074    /**
1075     * The idle object evictor {@link TimerTask}.
1076     *
1077     * @see GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis
1078     */
1079    class Evictor implements Runnable {
1080
1081        private ScheduledFuture<?> scheduledFuture;
1082
1083        /**
1084         * Run pool maintenance.  Evict objects qualifying for eviction and then
1085         * ensure that the minimum number of idle instances are available.
1086         * Since the Timer that invokes Evictors is shared for all Pools but
1087         * pools may exist in different class loaders, the Evictor ensures that
1088         * any actions taken are under the class loader of the factory
1089         * associated with the pool.
1090         */
1091        @Override
1092        public void run() {
1093            final ClassLoader savedClassLoader =
1094                    Thread.currentThread().getContextClassLoader();
1095            try {
1096                if (factoryClassLoader != null) {
1097                    // Set the class loader for the factory
1098                    final ClassLoader cl = factoryClassLoader.get();
1099                    if (cl == null) {
1100                        // The pool has been dereferenced and the class loader
1101                        // GC'd. Cancel this timer so the pool can be GC'd as
1102                        // well.
1103                        cancel();
1104                        return;
1105                    }
1106                    Thread.currentThread().setContextClassLoader(cl);
1107                }
1108
1109                // Evict from the pool
1110                try {
1111                    evict();
1112                } catch(final Exception e) {
1113                    swallowException(e);
1114                } catch(final OutOfMemoryError oome) {
1115                    // Log problem but give evictor thread a chance to continue
1116                    // in case error is recoverable
1117                    oome.printStackTrace(System.err);
1118                }
1119                // Re-create idle instances.
1120                try {
1121                    ensureMinIdle();
1122                } catch (final Exception e) {
1123                    swallowException(e);
1124                }
1125            } finally {
1126                // Restore the previous CCL
1127                Thread.currentThread().setContextClassLoader(savedClassLoader);
1128            }
1129        }
1130
1131
1132        void setScheduledFuture(final ScheduledFuture<?> scheduledFuture) {
1133            this.scheduledFuture = scheduledFuture;
1134        }
1135
1136
1137        void cancel() {
1138            scheduledFuture.cancel(false);
1139        }
1140    }
1141
1142    /**
1143     * Maintains a cache of values for a single metric and reports
1144     * statistics on the cached values.
1145     */
1146    private class StatsStore {
1147
1148        private final AtomicLong values[];
1149        private final int size;
1150        private int index;
1151
1152        /**
1153         * Create a StatsStore with the given cache size.
1154         *
1155         * @param size number of values to maintain in the cache.
1156         */
1157        public StatsStore(final int size) {
1158            this.size = size;
1159            values = new AtomicLong[size];
1160            for (int i = 0; i < size; i++) {
1161                values[i] = new AtomicLong(-1);
1162            }
1163        }
1164
1165        /**
1166         * Adds a value to the cache.  If the cache is full, one of the
1167         * existing values is replaced by the new value.
1168         *
1169         * @param value new value to add to the cache.
1170         */
1171        public synchronized void add(final long value) {
1172            values[index].set(value);
1173            index++;
1174            if (index == size) {
1175                index = 0;
1176            }
1177        }
1178
1179        /**
1180         * Returns the mean of the cached values.
1181         *
1182         * @return the mean of the cache, truncated to long
1183         */
1184        public long getMean() {
1185            double result = 0;
1186            int counter = 0;
1187            for (int i = 0; i < size; i++) {
1188                final long value = values[i].get();
1189                if (value != -1) {
1190                    counter++;
1191                    result = result * ((counter - 1) / (double) counter) +
1192                            value/(double) counter;
1193                }
1194            }
1195            return (long) result;
1196        }
1197
1198        @Override
1199        public String toString() {
1200            final StringBuilder builder = new StringBuilder();
1201            builder.append("StatsStore [values=");
1202            builder.append(Arrays.toString(values));
1203            builder.append(", size=");
1204            builder.append(size);
1205            builder.append(", index=");
1206            builder.append(index);
1207            builder.append("]");
1208            return builder.toString();
1209        }
1210    }
1211
1212    /**
1213     * The idle object eviction iterator. Holds a reference to the idle objects.
1214     */
1215    class EvictionIterator implements Iterator<PooledObject<T>> {
1216
1217        private final Deque<PooledObject<T>> idleObjects;
1218        private final Iterator<PooledObject<T>> idleObjectIterator;
1219
1220        /**
1221         * Create an EvictionIterator for the provided idle instance deque.
1222         * @param idleObjects underlying deque
1223         */
1224        EvictionIterator(final Deque<PooledObject<T>> idleObjects) {
1225            this.idleObjects = idleObjects;
1226
1227            if (getLifo()) {
1228                idleObjectIterator = idleObjects.descendingIterator();
1229            } else {
1230                idleObjectIterator = idleObjects.iterator();
1231            }
1232        }
1233
1234        /**
1235         * Returns the idle object deque referenced by this iterator.
1236         * @return the idle object deque
1237         */
1238        public Deque<PooledObject<T>> getIdleObjects() {
1239            return idleObjects;
1240        }
1241
1242        /** {@inheritDoc} */
1243        @Override
1244        public boolean hasNext() {
1245            return idleObjectIterator.hasNext();
1246        }
1247
1248        /** {@inheritDoc} */
1249        @Override
1250        public PooledObject<T> next() {
1251            return idleObjectIterator.next();
1252        }
1253
1254        /** {@inheritDoc} */
1255        @Override
1256        public void remove() {
1257            idleObjectIterator.remove();
1258        }
1259
1260    }
1261
1262    /**
1263     * Wrapper for objects under management by the pool.
1264     *
1265     * GenericObjectPool and GenericKeyedObjectPool maintain references to all
1266     * objects under management using maps keyed on the objects. This wrapper
1267     * class ensures that objects can work as hash keys.
1268     *
1269     * @param <T> type of objects in the pool
1270     */
1271    static class IdentityWrapper<T> {
1272        /** Wrapped object */
1273        private final T instance;
1274
1275        /**
1276         * Create a wrapper for an instance.
1277         *
1278         * @param instance object to wrap
1279         */
1280        public IdentityWrapper(final T instance) {
1281            this.instance = instance;
1282        }
1283
1284        @Override
1285        public int hashCode() {
1286            return System.identityHashCode(instance);
1287        }
1288
1289        @Override
1290        @SuppressWarnings("rawtypes")
1291        public boolean equals(final Object other) {
1292            return  other instanceof IdentityWrapper &&
1293                    ((IdentityWrapper) other).instance == instance;
1294        }
1295
1296        /**
1297         * @return the wrapped object
1298         */
1299        public T getObject() {
1300            return instance;
1301        }
1302
1303        @Override
1304        public String toString() {
1305            final StringBuilder builder = new StringBuilder();
1306            builder.append("IdentityWrapper [instance=");
1307            builder.append(instance);
1308            builder.append("]");
1309            return builder.toString();
1310        }
1311    }
1312
1313    @Override
1314    protected void toStringAppendFields(final StringBuilder builder) {
1315        builder.append("maxTotal=");
1316        builder.append(maxTotal);
1317        builder.append(", blockWhenExhausted=");
1318        builder.append(blockWhenExhausted);
1319        builder.append(", maxWaitMillis=");
1320        builder.append(maxWaitMillis);
1321        builder.append(", lifo=");
1322        builder.append(lifo);
1323        builder.append(", fairness=");
1324        builder.append(fairness);
1325        builder.append(", testOnCreate=");
1326        builder.append(testOnCreate);
1327        builder.append(", testOnBorrow=");
1328        builder.append(testOnBorrow);
1329        builder.append(", testOnReturn=");
1330        builder.append(testOnReturn);
1331        builder.append(", testWhileIdle=");
1332        builder.append(testWhileIdle);
1333        builder.append(", timeBetweenEvictionRunsMillis=");
1334        builder.append(timeBetweenEvictionRunsMillis);
1335        builder.append(", numTestsPerEvictionRun=");
1336        builder.append(numTestsPerEvictionRun);
1337        builder.append(", minEvictableIdleTimeMillis=");
1338        builder.append(minEvictableIdleTimeMillis);
1339        builder.append(", softMinEvictableIdleTimeMillis=");
1340        builder.append(softMinEvictableIdleTimeMillis);
1341        builder.append(", evictionPolicy=");
1342        builder.append(evictionPolicy);
1343        builder.append(", closeLock=");
1344        builder.append(closeLock);
1345        builder.append(", closed=");
1346        builder.append(closed);
1347        builder.append(", evictionLock=");
1348        builder.append(evictionLock);
1349        builder.append(", evictor=");
1350        builder.append(evictor);
1351        builder.append(", evictionIterator=");
1352        builder.append(evictionIterator);
1353        builder.append(", factoryClassLoader=");
1354        builder.append(factoryClassLoader);
1355        builder.append(", oname=");
1356        builder.append(objectName);
1357        builder.append(", creationStackTrace=");
1358        builder.append(creationStackTrace);
1359        builder.append(", borrowedCount=");
1360        builder.append(borrowedCount);
1361        builder.append(", returnedCount=");
1362        builder.append(returnedCount);
1363        builder.append(", createdCount=");
1364        builder.append(createdCount);
1365        builder.append(", destroyedCount=");
1366        builder.append(destroyedCount);
1367        builder.append(", destroyedByEvictorCount=");
1368        builder.append(destroyedByEvictorCount);
1369        builder.append(", destroyedByBorrowValidationCount=");
1370        builder.append(destroyedByBorrowValidationCount);
1371        builder.append(", activeTimes=");
1372        builder.append(activeTimes);
1373        builder.append(", idleTimes=");
1374        builder.append(idleTimes);
1375        builder.append(", waitTimes=");
1376        builder.append(waitTimes);
1377        builder.append(", maxBorrowWaitTimeMillis=");
1378        builder.append(maxBorrowWaitTimeMillis);
1379        builder.append(", swallowedExceptionListener=");
1380        builder.append(swallowedExceptionListener);
1381    }
1382
1383
1384}