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