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