1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.tomcat.dbcp.pool2.impl;
18
19 import java.io.PrintWriter;
20 import java.io.StringWriter;
21 import java.io.Writer;
22 import java.lang.management.ManagementFactory;
23 import java.lang.ref.WeakReference;
24 import java.lang.reflect.InvocationTargetException;
25 import java.util.Arrays;
26 import java.util.Deque;
27 import java.util.Iterator;
28 import java.util.TimerTask;
29 import java.util.concurrent.ScheduledFuture;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.atomic.AtomicLong;
32
33 import javax.management.InstanceAlreadyExistsException;
34 import javax.management.InstanceNotFoundException;
35 import javax.management.MBeanRegistrationException;
36 import javax.management.MBeanServer;
37 import javax.management.MalformedObjectNameException;
38 import javax.management.NotCompliantMBeanException;
39 import javax.management.ObjectName;
40
41 import org.apache.tomcat.dbcp.pool2.BaseObject;
42 import org.apache.tomcat.dbcp.pool2.PooledObject;
43 import org.apache.tomcat.dbcp.pool2.PooledObjectState;
44 import org.apache.tomcat.dbcp.pool2.SwallowedExceptionListener;
45
46 /**
47 * Base class that provides common functionality for {@link GenericObjectPool}
48 * and {@link GenericKeyedObjectPool}. The primary reason this class exists is
49 * reduce code duplication between the two pool implementations.
50 *
51 * @param <T> Type of element pooled in this pool.
52 *
53 * This class is intended to be thread-safe.
54 *
55 * @since 2.0
56 */
57 public abstract class BaseGenericObjectPool<T> extends BaseObject {
58
59 // Constants
60 /**
61 * The size of the caches used to store historical data for some attributes
62 * so that rolling means may be calculated.
63 */
64 public static final int MEAN_TIMING_STATS_CACHE_SIZE = 100;
65
66 private static final String EVICTION_POLICY_TYPE_NAME = EvictionPolicy.class.getName();
67
68 // Configuration attributes
69 private volatile int maxTotal =
70 GenericKeyedObjectPoolConfig.DEFAULT_MAX_TOTAL;
71 private volatile boolean blockWhenExhausted =
72 BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
73 private volatile long maxWaitMillis =
74 BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
75 private volatile boolean lifo = BaseObjectPoolConfig.DEFAULT_LIFO;
76 private final boolean fairness;
77 private volatile boolean testOnCreate =
78 BaseObjectPoolConfig.DEFAULT_TEST_ON_CREATE;
79 private volatile boolean testOnBorrow =
80 BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW;
81 private volatile boolean testOnReturn =
82 BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN;
83 private volatile boolean testWhileIdle =
84 BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE;
85 private volatile long timeBetweenEvictionRunsMillis =
86 BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
87 private volatile int numTestsPerEvictionRun =
88 BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN;
89 private volatile long minEvictableIdleTimeMillis =
90 BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
91 private volatile long softMinEvictableIdleTimeMillis =
92 BaseObjectPoolConfig.DEFAULT_SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
93 private volatile EvictionPolicy<T> evictionPolicy;
94 private volatile long evictorShutdownTimeoutMillis =
95 BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT_MILLIS;
96
97
98 // Internal (primarily state) attributes
99 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 stopEvictor() {
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 }
1412