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