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