View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.pool2.impl;
18  
19  import java.time.Duration;
20  import java.time.Instant;
21  import java.util.ArrayList;
22  import java.util.NoSuchElementException;
23  import java.util.Set;
24  import java.util.concurrent.ConcurrentHashMap;
25  import java.util.concurrent.atomic.AtomicLong;
26  import java.util.stream.Collectors;
27  
28  import org.apache.commons.pool2.DestroyMode;
29  import org.apache.commons.pool2.ObjectPool;
30  import org.apache.commons.pool2.PoolUtils;
31  import org.apache.commons.pool2.PooledObject;
32  import org.apache.commons.pool2.PooledObjectFactory;
33  import org.apache.commons.pool2.PooledObjectState;
34  import org.apache.commons.pool2.SwallowedExceptionListener;
35  import org.apache.commons.pool2.TrackedUse;
36  import org.apache.commons.pool2.UsageTracking;
37  
38  /**
39   * A configurable {@link ObjectPool} implementation.
40   * <p>
41   * When coupled with the appropriate {@link PooledObjectFactory},
42   * {@code GenericObjectPool} provides robust pooling functionality for
43   * arbitrary objects.
44   * </p>
45   * <p>
46   * Optionally, one may configure the pool to examine and possibly evict objects
47   * as they sit idle in the pool and to ensure that a minimum number of idle
48   * objects are available. This is performed by an "idle object eviction" thread,
49   * which runs asynchronously. Caution should be used when configuring this
50   * optional feature. Eviction runs contend with client threads for access to
51   * objects in the pool, so if they run too frequently performance issues may
52   * result.
53   * </p>
54   * <p>
55   * The pool can also be configured to detect and remove "abandoned" objects,
56   * i.e. objects that have been checked out of the pool but neither used nor
57   * returned before the configured
58   * {@link AbandonedConfig#getRemoveAbandonedTimeoutDuration() removeAbandonedTimeout}.
59   * Abandoned object removal can be configured to happen when
60   * {@code borrowObject} is invoked and the pool is close to starvation, or
61   * it can be executed by the idle object evictor, or both. If pooled objects
62   * implement the {@link TrackedUse} interface, their last use will be queried
63   * using the {@code getLastUsed} method on that interface; otherwise
64   * abandonment is determined by how long an object has been checked out from
65   * the pool.
66   * </p>
67   * <p>
68   * Implementation note: To prevent possible deadlocks, care has been taken to
69   * ensure that no call to a factory method will occur within a synchronization
70   * block. See POOL-125 and DBCP-44 for more information.
71   * </p>
72   * <p>
73   * This class is intended to be thread-safe.
74   * </p>
75   *
76   * @see GenericKeyedObjectPool
77   * @param <T> Type of element pooled in this pool.
78   * @since 2.0
79   */
80  public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
81          implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
82  
83      // JMX specific attributes
84      private static final String ONAME_BASE =
85          "org.apache.commons.pool2:type=GenericObjectPool,name=";
86  
87      private volatile String factoryType;
88  
89      private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
90  
91      private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
92  
93      private final PooledObjectFactory<T> factory;
94  
95      /*
96       * All of the objects currently associated with this pool in any state. It
97       * excludes objects that have been destroyed. The size of
98       * {@link #allObjects} will always be less than or equal to {@link
99       * #getMaxTotal()}. Map keys are pooled objects, values are the PooledObject
100      * wrappers used internally by the pool.
101      */
102     private final ConcurrentHashMap<IdentityWrapper<T>, PooledObject<T>> allObjects = new ConcurrentHashMap<>();
103 
104     /*
105      * The combined count of the currently created objects and those in the
106      * process of being created. Under load, it may exceed {@link #getMaxTotal()}
107      * if multiple threads try and create a new object at the same time but
108      * {@link #create()} will ensure that there are never more than
109      * {@link #getMaxTotal()} objects created at any one time.
110      */
111     private final AtomicLong createCount = new AtomicLong();
112 
113     private long makeObjectCount;
114 
115     private final Object makeObjectCountLock = new Object();
116 
117     private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
118 
119     /**
120      * Creates a new {@code GenericObjectPool} using defaults from
121      * {@link GenericObjectPoolConfig}.
122      *
123      * @param factory The object factory to be used to create object instances
124      *                used by this pool
125      */
126     public GenericObjectPool(final PooledObjectFactory<T> factory) {
127         this(factory, new GenericObjectPoolConfig<>());
128     }
129 
130     /**
131      * Creates a new {@code GenericObjectPool} using a specific
132      * configuration.
133      *
134      * @param factory   The object factory to be used to create object instances
135      *                  used by this pool
136      * @param config    The configuration to use for this pool instance. The
137      *                  configuration is used by value. Subsequent changes to
138      *                  the configuration object will not be reflected in the
139      *                  pool.
140      */
141     public GenericObjectPool(final PooledObjectFactory<T> factory,
142             final GenericObjectPoolConfig<T> config) {
143 
144         super(config, ONAME_BASE, config.getJmxNamePrefix());
145 
146         if (factory == null) {
147             jmxUnregister(); // tidy up
148             throw new IllegalArgumentException("Factory may not be null");
149         }
150         this.factory = factory;
151 
152         idleObjects = new LinkedBlockingDeque<>(config.getFairness());
153 
154         setConfig(config);
155     }
156 
157     /**
158      * Creates a new {@code GenericObjectPool} that tracks and destroys
159      * objects that are checked out, but never returned to the pool.
160      *
161      * @param factory   The object factory to be used to create object instances
162      *                  used by this pool
163      * @param config    The base pool configuration to use for this pool instance.
164      *                  The configuration is used by value. Subsequent changes to
165      *                  the configuration object will not be reflected in the
166      *                  pool.
167      * @param abandonedConfig  Configuration for abandoned object identification
168      *                         and removal.  The configuration is used by value.
169      */
170     public GenericObjectPool(final PooledObjectFactory<T> factory,
171             final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
172         this(factory, config);
173         setAbandonedConfig(abandonedConfig);
174     }
175 
176     /**
177      * Adds the provided wrapped pooled object to the set of idle objects for
178      * this pool. The object must already be part of the pool.  If {@code p}
179      * is null, this is a no-op (no exception, but no impact on the pool).
180      *
181      * @param p The object to make idle
182      * @throws Exception If the factory fails to passivate the object
183      */
184     private void addIdleObject(final PooledObject<T> p) throws Exception {
185         if (PooledObject.nonNull(p)) {
186             factory.passivateObject(p);
187             if (getLifo()) {
188                 idleObjects.addFirst(p);
189             } else {
190                 idleObjects.addLast(p);
191             }
192         }
193     }
194 
195     /**
196      * Creates an object, and places it into the pool. addObject() is useful for
197      * "pre-loading" a pool with idle objects.
198      * <p>
199      * If there is no capacity available to add to the pool, or there are already
200      * {@link #getMaxIdle()} idle instances in the pool, this is a no-op
201      * (no exception, no impact to the pool).
202      * </p>
203      * <p>
204      * If the factory returns null when creating an object, a {@code NullPointerException}
205      * is thrown. If there is no factory set (factory == null), an {@code IllegalStateException}
206      * is thrown.
207      * </p>
208      */
209     @Override
210     public void addObject() throws Exception {
211         assertOpen();
212         if (factory == null) {
213             throw new IllegalStateException("Cannot add objects without a factory.");
214         }
215         final int localMaxIdle = getMaxIdle();
216         final int localMaxTotal = getMaxTotal();
217         if ((localMaxIdle < 0 || getNumIdle() < localMaxIdle) &&
218                 (localMaxTotal < 0 || createCount.get() < localMaxTotal)) {
219             addIdleObject(create(getMaxWaitDuration()));
220         }
221     }
222 
223     /**
224      * Equivalent to <code>{@link #borrowObject(Duration)
225      * borrowObject}({@link #getMaxWaitDuration()})</code>.
226      *
227      * {@inheritDoc}
228      */
229     @Override
230     public T borrowObject() throws Exception {
231         return borrowObject(getMaxWaitDuration());
232     }
233 
234     /**
235      * Borrows an object from the pool using the specific waiting time which only
236      * applies if {@link #getBlockWhenExhausted()} is true.
237      * <p>
238      * If there is one or more idle instance available in the pool, then an
239      * idle instance will be selected based on the value of {@link #getLifo()},
240      * activated and returned. If activation fails, or {@link #getTestOnBorrow()
241      * testOnBorrow} is set to {@code true} and validation fails, the
242      * instance is destroyed and the next available instance is examined. This
243      * continues until either a valid instance is returned or there are no more
244      * idle instances available.
245      * </p>
246      * <p>
247      * If there are no idle instances available in the pool, behavior depends on
248      * the {@link #getMaxTotal() maxTotal}, (if applicable)
249      * {@link #getBlockWhenExhausted()} and the value passed in the
250      * {@code maxWaitDuration} parameter. If the number of instances
251      * checked out from the pool is less than {@code maxTotal,} a new
252      * instance is created, activated and (if applicable) validated and returned
253      * to the caller. If validation fails, a {@code NoSuchElementException}
254      * is thrown. If the factory returns null when creating an instance,
255      * a {@code NullPointerException} is thrown.
256      * </p>
257      * <p>
258      * If the pool is exhausted (no available idle instances and no capacity to
259      * create new ones), this method will either block (if
260      * {@link #getBlockWhenExhausted()} is true) or throw a
261      * {@code NoSuchElementException} (if
262      * {@link #getBlockWhenExhausted()} is false). The length of time that this
263      * method will block when {@link #getBlockWhenExhausted()} is true is
264      * determined by the value passed in to the {@code maxWaitDuration}
265      * parameter. Passing a negative duration will cause this method to block
266      * indefinitely until an object becomes available.
267      * </p>
268      * <p>
269      * When the pool is exhausted, multiple calling threads may be
270      * simultaneously blocked waiting for instances to become available. A
271      * "fairness" algorithm has been implemented to ensure that threads receive
272      * available instances in request arrival order.
273      * </p>
274      *
275      * @param maxWaitDuration The time to wait for an object to become available, not null.
276      * @return object instance from the pool
277      * @throws NoSuchElementException if an instance cannot be returned
278      * @throws Exception if an object instance cannot be returned due to an error
279      * @since 2.10.0
280      */
281     public T borrowObject(final Duration maxWaitDuration) throws Exception {
282         assertOpen();
283         final Instant startInstant = Instant.now();
284         final boolean negativeDuration = maxWaitDuration.isNegative();
285         Duration remainingWaitDuration = maxWaitDuration;
286         final AbandonedConfig ac = this.abandonedConfig;
287         if (ac != null && ac.getRemoveAbandonedOnBorrow() && getNumIdle() < 2 && getNumActive() > getMaxTotal() - 3) {
288             removeAbandoned(ac);
289         }
290         PooledObject<T> p = null;
291         // Get local copy of current config so it is consistent for entire
292         // method execution
293         final boolean blockWhenExhausted = getBlockWhenExhausted();
294         boolean create;
295         while (p == null) {
296             remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
297             create = false;
298             p = idleObjects.pollFirst();
299             if (p == null) {
300                 p = create(remainingWaitDuration);
301                 if (PooledObject.nonNull(p)) {
302                     create = true;
303                 }
304             }
305             if (blockWhenExhausted) {
306                 if (PooledObject.isNull(p)) {
307                     remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
308                     p = negativeDuration ? idleObjects.takeFirst() : idleObjects.pollFirst(remainingWaitDuration);
309                 }
310                 if (PooledObject.isNull(p)) {
311                     throw new NoSuchElementException(appendStats("Timeout waiting for idle object, maxWaitDuration=" + remainingWaitDuration));
312                 }
313             } else if (PooledObject.isNull(p)) {
314                 throw new NoSuchElementException(appendStats("Pool exhausted"));
315             }
316             if (!p.allocate()) {
317                 p = null;
318             }
319             if (!PooledObject.isNull(p)) {
320                 try {
321                     factory.activateObject(p);
322                 } catch (final Exception e) {
323                     try {
324                         destroy(p, DestroyMode.NORMAL);
325                     } catch (final Exception ignored) {
326                         // ignored - activation failure is more important
327                     }
328                     p = null;
329                     if (create) {
330                         final NoSuchElementException nsee = new NoSuchElementException(appendStats("Unable to activate object"));
331                         nsee.initCause(e);
332                         throw nsee;
333                     }
334                 }
335                 if (!PooledObject.isNull(p) && getTestOnBorrow()) {
336                     boolean validate = false;
337                     Throwable validationThrowable = null;
338                     try {
339                         validate = factory.validateObject(p);
340                     } catch (final Throwable t) {
341                         PoolUtils.checkRethrow(t);
342                         validationThrowable = t;
343                     }
344                     if (!validate) {
345                         try {
346                             destroy(p, DestroyMode.NORMAL);
347                             destroyedByBorrowValidationCount.incrementAndGet();
348                         } catch (final Exception ignored) {
349                             // ignored - validation failure is more important
350                         }
351                         p = null;
352                         if (create) {
353                             final NoSuchElementException nsee = new NoSuchElementException(appendStats("Unable to validate object"));
354                             nsee.initCause(validationThrowable);
355                             throw nsee;
356                         }
357                     }
358                 }
359             }
360         }
361         updateStatsBorrow(p, durationSince(startInstant));
362         return p.getObject();
363     }
364 
365     /**
366      * Borrows an object from the pool using the specific waiting time which only
367      * applies if {@link #getBlockWhenExhausted()} is true.
368      * <p>
369      * If there is one or more idle instance available in the pool, then an
370      * idle instance will be selected based on the value of {@link #getLifo()},
371      * activated and returned. If activation fails, or {@link #getTestOnBorrow()
372      * testOnBorrow} is set to {@code true} and validation fails, the
373      * instance is destroyed and the next available instance is examined. This
374      * continues until either a valid instance is returned or there are no more
375      * idle instances available.
376      * </p>
377      * <p>
378      * If there are no idle instances available in the pool, behavior depends on
379      * the {@link #getMaxTotal() maxTotal}, (if applicable)
380      * {@link #getBlockWhenExhausted()} and the value passed in to the
381      * {@code maxWaitMillis} parameter. If the number of instances
382      * checked out from the pool is less than {@code maxTotal,} a new
383      * instance is created, activated and (if applicable) validated and returned
384      * to the caller. If validation fails, a {@code NoSuchElementException}
385      * is thrown. If the factory returns null when creating an instance,
386      * a {@code NullPointerException} is thrown.
387      * </p>
388      * <p>
389      * If the pool is exhausted (no available idle instances and no capacity to
390      * create new ones), this method will either block (if
391      * {@link #getBlockWhenExhausted()} is true) or throw a
392      * {@code NoSuchElementException} (if
393      * {@link #getBlockWhenExhausted()} is false). The length of time that this
394      * method will block when {@link #getBlockWhenExhausted()} is true is
395      * determined by the value passed in to the {@code maxWaitMillis}
396      * parameter.  Passing a negative duration will cause this method to block
397      * indefinitely until an object becomes available.
398      * </p>
399      * <p>
400      * When the pool is exhausted, multiple calling threads may be
401      * simultaneously blocked waiting for instances to become available. A
402      * "fairness" algorithm has been implemented to ensure that threads receive
403      * available instances in request arrival order.
404      * </p>
405      *
406      * @param maxWaitMillis The time to wait in milliseconds for an object
407      *                            to become available
408      * @return object instance from the pool
409      * @throws NoSuchElementException if an instance cannot be returned
410      * @throws Exception if an object instance cannot be returned due to an
411      *                   error
412      * @deprecated Use {@link #borrowObject(Duration)}.
413      */
414     @Deprecated
415     public T borrowObject(final long maxWaitMillis) throws Exception {
416         return borrowObject(Duration.ofMillis(maxWaitMillis));
417     }
418 
419     /**
420      * Clears any objects sitting idle in the pool by removing them from the
421      * idle instance pool and then invoking the configured
422      * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each
423      * idle instance.
424      * <p>
425      * Implementation notes:
426      * </p>
427      * <ul>
428      * <li>This method does not destroy or effect in any way instances that are
429      * checked out of the pool when it is invoked.</li>
430      * <li>Invoking this method does not prevent objects being returned to the
431      * idle instance pool, even during its execution. Additional instances may
432      * be returned while removed items are being destroyed.</li>
433      * <li>Exceptions encountered destroying idle instances are swallowed
434      * but notified via a {@link SwallowedExceptionListener}.</li>
435      * </ul>
436      */
437     @Override
438     public void clear() {
439         PooledObject<T> p = idleObjects.poll();
440 
441         while (p != null) {
442             try {
443                 destroy(p, DestroyMode.NORMAL);
444             } catch (final Exception e) {
445                 swallowException(e);
446             }
447             p = idleObjects.poll();
448         }
449     }
450 
451     /**
452      * Closes the pool. Once the pool is closed, {@link #borrowObject()} will
453      * fail with IllegalStateException, but {@link #returnObject(Object)} and
454      * {@link #invalidateObject(Object)} will continue to work, with returned
455      * objects destroyed on return.
456      * <p>
457      * Destroys idle instances in the pool by invoking {@link #clear()}.
458      * </p>
459      */
460     @Override
461     public void close() {
462         if (isClosed()) {
463             return;
464         }
465 
466         synchronized (closeLock) {
467             if (isClosed()) {
468                 return;
469             }
470 
471             // Stop the evictor before the pool is closed since evict() calls
472             // assertOpen()
473             stopEvictor();
474 
475             closed = true;
476             // This clear removes any idle objects
477             clear();
478 
479             jmxUnregister();
480 
481             // Release any threads that were waiting for an object
482             idleObjects.interruptTakeWaiters();
483         }
484     }
485 
486     /**
487      * Attempts to create a new wrapped pooled object.
488      * <p>
489      * If there are {@link #getMaxTotal()} objects already in circulation or in process of being created, this method
490      * returns null.
491      * </p>
492      * <p>
493      * If the factory makeObject returns null, this method throws a NullPointerException.
494      * </p>
495      *
496      * @param maxWaitDurationRequest The time to wait for capacity to create.
497      * @return The new wrapped pooled object or null.
498      * @throws Exception if the object factory's {@code makeObject} fails.
499      */
500     private PooledObject<T> create(final Duration maxWaitDurationRequest) throws Exception {
501         final Instant startInstant = Instant.now();
502         final Duration maxWaitDuration = maxWaitDurationRequest.isNegative() ? Duration.ZERO : maxWaitDurationRequest;
503         int localMaxTotal = getMaxTotal();
504         // This simplifies the code later in this method
505         if (localMaxTotal < 0) {
506             localMaxTotal = Integer.MAX_VALUE;
507         }
508         final Instant localStartInstant = Instant.now();
509         // Flag that indicates if create should:
510         // - TRUE:  call the factory to create an object
511         // - FALSE: return null
512         // - null:  loop and re-test the condition that determines whether to
513         //          call the factory
514         Boolean create = null;
515         while (create == null) {
516             // remainingWaitDuration handles spurious wakeup from wait().
517             final Duration remainingWaitDuration = maxWaitDuration.minus(durationSince(startInstant));
518             synchronized (makeObjectCountLock) {
519                 final long newCreateCount = createCount.incrementAndGet();
520                 if (newCreateCount > localMaxTotal) {
521                     // The pool is currently at capacity or in the process of
522                     // making enough new objects to take it to capacity.
523                     createCount.decrementAndGet();
524                     if (makeObjectCount == 0) {
525                         // There are no makeObject() calls in progress so the
526                         // pool is at capacity. Do not attempt to create a new
527                         // object. Return and wait for an object to be returned
528                         create = Boolean.FALSE;
529                     } else {
530                         // There are makeObject() calls in progress that might
531                         // bring the pool to capacity. Those calls might also
532                         // fail so wait until they complete and then re-test if
533                         // the pool is at capacity or not.
534                         wait(makeObjectCountLock, remainingWaitDuration);
535                     }
536                 } else {
537                     // The pool is not at capacity. Create a new object.
538                     makeObjectCount++;
539                     create = Boolean.TRUE;
540                 }
541             }
542             // Do not block more if remainingWaitDuration > 0.
543             if (create == null && remainingWaitDuration.compareTo(Duration.ZERO) > 0 &&
544                     durationSince(localStartInstant).compareTo(remainingWaitDuration) >= 0) {
545                 create = Boolean.FALSE;
546             }
547         }
548 
549         if (!create.booleanValue()) {
550             return null;
551         }
552 
553         final PooledObject<T> p;
554         try {
555             p = factory.makeObject();
556             if (PooledObject.isNull(p)) {
557                 createCount.decrementAndGet();
558                 throw new NullPointerException(String.format("%s.makeObject() = null", factory.getClass().getSimpleName()));
559             }
560             if (getTestOnCreate() && !factory.validateObject(p)) {
561                 createCount.decrementAndGet();
562                 return null;
563             }
564         } catch (final Throwable e) {
565             createCount.decrementAndGet();
566             throw e;
567         } finally {
568             synchronized (makeObjectCountLock) {
569                 makeObjectCount--;
570                 makeObjectCountLock.notifyAll();
571             }
572         }
573 
574         final AbandonedConfig ac = this.abandonedConfig;
575         if (ac != null && ac.getLogAbandoned()) {
576             p.setLogAbandoned(true);
577             p.setRequireFullStackTrace(ac.getRequireFullStackTrace());
578         }
579 
580         createdCount.incrementAndGet();
581         allObjects.put(IdentityWrapper.unwrap(p), p);
582         return p;
583     }
584 
585     /**
586      * Destroys a wrapped pooled object.
587      *
588      * @param toDestroy The wrapped pooled object to destroy
589      * @param destroyMode DestroyMode context provided to the factory
590      * @throws Exception If the factory fails to destroy the pooled object
591      *                   cleanly
592      */
593     private void destroy(final PooledObject<T> toDestroy, final DestroyMode destroyMode) throws Exception {
594         toDestroy.invalidate();
595         idleObjects.remove(toDestroy);
596         allObjects.remove(IdentityWrapper.unwrap(toDestroy));
597         try {
598             factory.destroyObject(toDestroy, destroyMode);
599         } finally {
600             destroyedCount.incrementAndGet();
601             createCount.decrementAndGet();
602         }
603     }
604 
605 
606     /**
607      * Tries to ensure that {@code idleCount} idle instances exist in the pool.
608      * <p>
609      * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount}
610      * or the total number of objects (idle, checked out, or being created) reaches
611      * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless
612      * there are threads waiting to check out instances from the pool.
613      * </p>
614      * <p>
615      * If the factory returns null when creating an instance, a {@code NullPointerException}
616      * is thrown.
617      * </p>
618      *
619      * @param idleCount the number of idle instances desired
620      * @param always true means create instances even if the pool has no threads waiting
621      * @throws Exception if the factory's makeObject throws
622      */
623     private void ensureIdle(final int idleCount, final boolean always) throws Exception {
624         if (idleCount < 1 || isClosed() || !always && !idleObjects.hasTakeWaiters()) {
625             return;
626         }
627 
628         while (idleObjects.size() < idleCount) {
629             final PooledObject<T> p = create(getMaxWaitDuration());
630             if (PooledObject.isNull(p)) {
631                 // Can't create objects, no reason to think another call to
632                 // create will work. Give up.
633                 break;
634             }
635             if (getLifo()) {
636                 idleObjects.addFirst(p);
637             } else {
638                 idleObjects.addLast(p);
639             }
640         }
641         if (isClosed()) {
642             // Pool closed while object was being added to idle objects.
643             // Make sure the returned object is destroyed rather than left
644             // in the idle object pool (which would effectively be a leak)
645             clear();
646         }
647     }
648 
649     @Override
650     void ensureMinIdle() throws Exception {
651         ensureIdle(getMinIdle(), true);
652     }
653 
654     /**
655      * {@inheritDoc}
656      * <p>
657      * Successive activations of this method examine objects in sequence,
658      * cycling through objects in oldest-to-youngest order.
659      * </p>
660      */
661     @Override
662     public void evict() throws Exception {
663         assertOpen();
664 
665         if (!idleObjects.isEmpty()) {
666 
667             PooledObject<T> underTest = null;
668             final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
669 
670             synchronized (evictionLock) {
671                 final EvictionConfig evictionConfig = new EvictionConfig(
672                         getMinEvictableIdleDuration(),
673                         getSoftMinEvictableIdleDuration(),
674                         getMinIdle());
675 
676                 final boolean testWhileIdle = getTestWhileIdle();
677 
678                 for (int i = 0, m = getNumTests(); i < m; i++) {
679                     if (evictionIterator == null || !evictionIterator.hasNext()) {
680                         evictionIterator = new EvictionIterator(idleObjects);
681                     }
682                     if (!evictionIterator.hasNext()) {
683                         // Pool exhausted, nothing to do here
684                         return;
685                     }
686 
687                     try {
688                         underTest = evictionIterator.next();
689                     } catch (final NoSuchElementException nsee) {
690                         // Object was borrowed in another thread
691                         // Don't count this as an eviction test so reduce i;
692                         i--;
693                         evictionIterator = null;
694                         continue;
695                     }
696 
697                     if (!underTest.startEvictionTest()) {
698                         // Object was borrowed in another thread
699                         // Don't count this as an eviction test so reduce i;
700                         i--;
701                         continue;
702                     }
703 
704                     // User provided eviction policy could throw all sorts of
705                     // crazy exceptions. Protect against such an exception
706                     // killing the eviction thread.
707                     boolean evict;
708                     try {
709                         evict = evictionPolicy.evict(evictionConfig, underTest,
710                                 idleObjects.size());
711                     } catch (final Throwable t) {
712                         // Slightly convoluted as SwallowedExceptionListener
713                         // uses Exception rather than Throwable
714                         PoolUtils.checkRethrow(t);
715                         swallowException(new Exception(t));
716                         // Don't evict on error conditions
717                         evict = false;
718                     }
719 
720                     if (evict) {
721                         destroy(underTest, DestroyMode.NORMAL);
722                         destroyedByEvictorCount.incrementAndGet();
723                     } else {
724                         if (testWhileIdle) {
725                             boolean active = false;
726                             try {
727                                 factory.activateObject(underTest);
728                                 active = true;
729                             } catch (final Exception e) {
730                                 destroy(underTest, DestroyMode.NORMAL);
731                                 destroyedByEvictorCount.incrementAndGet();
732                             }
733                             if (active) {
734                                 boolean validate = false;
735                                 Throwable validationThrowable = null;
736                                 try {
737                                     validate = factory.validateObject(underTest);
738                                 } catch (final Throwable t) {
739                                     PoolUtils.checkRethrow(t);
740                                     validationThrowable = t;
741                                 }
742                                 if (!validate) {
743                                     destroy(underTest, DestroyMode.NORMAL);
744                                     destroyedByEvictorCount.incrementAndGet();
745                                     if (validationThrowable != null) {
746                                         if (validationThrowable instanceof RuntimeException) {
747                                             throw (RuntimeException) validationThrowable;
748                                         }
749                                         throw (Error) validationThrowable;
750                                     }
751                                 } else {
752                                     try {
753                                         factory.passivateObject(underTest);
754                                     } catch (final Exception e) {
755                                         destroy(underTest, DestroyMode.NORMAL);
756                                         destroyedByEvictorCount.incrementAndGet();
757                                     }
758                                 }
759                             }
760                         }
761                         underTest.endEvictionTest(idleObjects);
762                     }
763                 }
764             }
765         }
766         final AbandonedConfig ac = this.abandonedConfig;
767         if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
768             removeAbandoned(ac);
769         }
770     }
771 
772     /**
773      * Gets a reference to the factory used to create, destroy and validate
774      * the objects used by this pool.
775      *
776      * @return the factory
777      */
778     public PooledObjectFactory<T> getFactory() {
779         return factory;
780     }
781 
782     /**
783      * Gets the type - including the specific type rather than the generic -
784      * of the factory.
785      *
786      * @return A string representation of the factory type
787      */
788     @Override
789     public String getFactoryType() {
790         // Not thread safe. Accept that there may be multiple evaluations.
791         if (factoryType == null) {
792             final StringBuilder result = new StringBuilder();
793             result.append(factory.getClass().getName());
794             result.append('<');
795             final Class<?> pooledObjectType =
796                     PoolImplUtils.getFactoryType(factory.getClass());
797             result.append(pooledObjectType.getName());
798             result.append('>');
799             factoryType = result.toString();
800         }
801         return factoryType;
802     }
803 
804     /**
805      * Gets the cap on the number of "idle" instances in the pool. If maxIdle
806      * is set too low on heavily loaded systems it is possible you will see
807      * objects being destroyed and almost immediately new objects being created.
808      * This is a result of the active threads momentarily returning objects
809      * faster than they are requesting them, causing the number of idle
810      * objects to rise above maxIdle. The best value for maxIdle for heavily
811      * loaded system will vary but the default is a good starting point.
812      *
813      * @return the maximum number of "idle" instances that can be held in the
814      *         pool or a negative value if there is no limit
815      * @see #setMaxIdle
816      */
817     @Override
818     public int getMaxIdle() {
819         return maxIdle;
820     }
821 
822     /**
823      * Gets the target for the minimum number of idle objects to maintain in
824      * the pool. This setting only has an effect if it is positive and
825      * {@link #getDurationBetweenEvictionRuns()} is greater than zero. If this
826      * is the case, an attempt is made to ensure that the pool has the required
827      * minimum number of instances during idle object eviction runs.
828      * <p>
829      * If the configured value of minIdle is greater than the configured value
830      * for maxIdle then the value of maxIdle will be used instead.
831      * </p>
832      *
833      * @return The minimum number of objects.
834      * @see #setMinIdle(int)
835      * @see #setMaxIdle(int)
836      * @see #setDurationBetweenEvictionRuns(Duration)
837      */
838     @Override
839     public int getMinIdle() {
840         final int maxIdleSave = getMaxIdle();
841         return Math.min(this.minIdle, maxIdleSave);
842     }
843 
844     @Override
845     public int getNumActive() {
846         return allObjects.size() - idleObjects.size();
847     }
848 
849     @Override
850     public int getNumIdle() {
851         return idleObjects.size();
852     }
853 
854     /**
855      * Calculates the number of objects to test in a run of the idle object
856      * evictor.
857      *
858      * @return The number of objects to test for validity
859      */
860     private int getNumTests() {
861         final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
862         if (numTestsPerEvictionRun >= 0) {
863             return Math.min(numTestsPerEvictionRun, idleObjects.size());
864         }
865         return (int) Math.ceil(idleObjects.size() /
866                 Math.abs((double) numTestsPerEvictionRun));
867     }
868 
869     /**
870      * Gets an estimate of the number of threads currently blocked waiting for
871      * an object from the pool. This is intended for monitoring only, not for
872      * synchronization control.
873      *
874      * @return The estimate of the number of threads currently blocked waiting
875      *         for an object from the pool
876      */
877     @Override
878     public int getNumWaiters() {
879         if (getBlockWhenExhausted()) {
880             return idleObjects.getTakeQueueLength();
881         }
882         return 0;
883     }
884 
885     PooledObject<T> getPooledObject(final T obj) {
886         return allObjects.get(new IdentityWrapper<>(obj));
887     }
888 
889     @Override
890     String getStatsString() {
891         // Simply listed in AB order.
892         return super.getStatsString() +
893                 String.format(", createdCount=%,d, makeObjectCount=%,d, maxIdle=%,d, minIdle=%,d",
894                         createdCount.get(), makeObjectCount, maxIdle, minIdle);
895     }
896 
897     /**
898      * {@inheritDoc}
899      * <p>
900      * Activation of this method decrements the active count and attempts to destroy the instance, using the default
901      * (NORMAL) {@link DestroyMode}.
902      * </p>
903      *
904      * @throws Exception if an exception occurs destroying the
905      * @throws IllegalStateException if obj does not belong to this pool
906      */
907     @Override
908     public void invalidateObject(final T obj) throws Exception {
909         invalidateObject(obj, DestroyMode.NORMAL);
910     }
911 
912     /**
913      * {@inheritDoc}
914      * <p>
915      * Activation of this method decrements the active count and attempts to destroy the instance, using the provided
916      * {@link DestroyMode}. To ensure liveness of the pool, {@link #addObject()} is called to replace the invalidated
917      * instance.
918      * </p>
919      *
920      * @throws Exception if an exception occurs destroying the object
921      * @throws IllegalStateException if obj does not belong to this pool
922      * @since 2.9.0
923      */
924     @Override
925     public void invalidateObject(final T obj, final DestroyMode destroyMode) throws Exception {
926         final PooledObject<T> p = getPooledObject(obj);
927         if (p == null) {
928             if (isAbandonedConfig()) {
929                 return;
930             }
931             throw new IllegalStateException("Invalidated object not currently part of this pool");
932         }
933         synchronized (p) {
934             if (p.getState() != PooledObjectState.INVALID) {
935                 destroy(p, destroyMode);
936             }
937         }
938         if (!isClosed()) {
939              addObject();
940         }
941     }
942 
943     /**
944      * Provides information on all the objects in the pool, both idle (waiting
945      * to be borrowed) and active (currently borrowed).
946      * <p>
947      * Note: This is named listAllObjects so it is presented as an operation via
948      * JMX. That means it won't be invoked unless the explicitly requested
949      * whereas all attributes will be automatically requested when viewing the
950      * attributes for an object in a tool like JConsole.
951      * </p>
952      *
953      * @return Information grouped on all the objects in the pool
954      */
955     @Override
956     public Set<DefaultPooledObjectInfo> listAllObjects() {
957         return allObjects.values().stream().map(DefaultPooledObjectInfo::new).collect(Collectors.toSet());
958     }
959 
960     /**
961      * Tries to ensure that {@link #getMinIdle()} idle instances are available
962      * in the pool.
963      *
964      * @throws Exception If the associated factory throws an exception.
965      * @since 2.4
966      */
967     public void preparePool() throws Exception {
968         if (getMinIdle() < 1) {
969             return;
970         }
971         ensureMinIdle();
972     }
973 
974     /**
975      * Recovers abandoned objects which have been checked out but
976      * not used since longer than the removeAbandonedTimeout. For each object
977      * deemed abandoned, {@link #invalidateObject(Object)} is called. This
978      * results in the object being destroyed and then {@link #addObject()} is
979      * called to try to replace it.
980      *
981      * @param abandonedConfig The configuration to use to identify abandoned objects
982      */
983     @SuppressWarnings("resource") // PrintWriter is managed elsewhere
984     private void removeAbandoned(final AbandonedConfig abandonedConfig) {
985         // Generate a list of abandoned objects to remove
986         final ArrayList<PooledObject<T>> remove = createRemoveList(abandonedConfig, allObjects);
987         // Now remove the abandoned objects
988         remove.forEach(pooledObject -> {
989             if (abandonedConfig.getLogAbandoned()) {
990                 pooledObject.printStackTrace(abandonedConfig.getLogWriter());
991             }
992             try {
993                 invalidateObject(pooledObject.getObject(), DestroyMode.ABANDONED);
994             } catch (final Exception e) {
995                 swallowException(e);
996             }
997         });
998     }
999 
1000     /**
1001      * {@inheritDoc}
1002      * <p>
1003      * If {@link #getMaxIdle() maxIdle} is set to a positive value and the
1004      * number of idle instances has reached this value, the returning instance
1005      * is destroyed.
1006      * </p>
1007      * <p>
1008      * If {@link #getTestOnReturn() testOnReturn} == true, the returning
1009      * instance is validated before being returned to the idle instance pool. In
1010      * this case, if validation fails, the instance is destroyed.
1011      * </p>
1012      * <p>
1013      * Exceptions encountered destroying objects for any reason are swallowed
1014      * but notified via a {@link SwallowedExceptionListener}.
1015      * </p>
1016      */
1017     @Override
1018     public void returnObject(final T obj) {
1019         final PooledObject<T> p = getPooledObject(obj);
1020 
1021         if (p == null) {
1022             if (!isAbandonedConfig()) {
1023                 throw new IllegalStateException(
1024                         "Returned object not currently part of this pool");
1025             }
1026             return; // Object was abandoned and removed
1027         }
1028         synchronized (p) {
1029             markReturningState(p);
1030 
1031             final Duration activeTime = p.getActiveDuration();
1032 
1033             if (getTestOnReturn() && !factory.validateObject(p)) {
1034                 try {
1035                     destroy(p, DestroyMode.NORMAL);
1036                 } catch (final Exception e) {
1037                     swallowException(e);
1038                 }
1039                 try {
1040                     ensureIdle(1, false);
1041                 } catch (final Exception e) {
1042                     swallowException(e);
1043                 }
1044                 updateStatsReturn(activeTime);
1045                 return;
1046             }
1047 
1048             try {
1049                 factory.passivateObject(p);
1050             } catch (final Exception e1) {
1051                 swallowException(e1);
1052                 try {
1053                     destroy(p, DestroyMode.NORMAL);
1054                 } catch (final Exception e) {
1055                     swallowException(e);
1056                 }
1057                 try {
1058                     ensureIdle(1, false);
1059                 } catch (final Exception e) {
1060                     swallowException(e);
1061                 }
1062                 updateStatsReturn(activeTime);
1063                 return;
1064             }
1065 
1066             if (!p.deallocate()) {
1067                 throw new IllegalStateException(
1068                         "Object has already been returned to this pool or is invalid");
1069             }
1070 
1071             final int maxIdleSave = getMaxIdle();
1072             if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
1073                 try {
1074                     destroy(p, DestroyMode.NORMAL);
1075                 } catch (final Exception e) {
1076                     swallowException(e);
1077                 }
1078                 try {
1079                     ensureIdle(1, false);
1080                 } catch (final Exception e) {
1081                     swallowException(e);
1082                 }
1083             } else {
1084                 if (getLifo()) {
1085                     idleObjects.addFirst(p);
1086                 } else {
1087                     idleObjects.addLast(p);
1088                 }
1089                 if (isClosed()) {
1090                     // Pool closed while object was being added to idle objects.
1091                     // Make sure the returned object is destroyed rather than left
1092                     // in the idle object pool (which would effectively be a leak)
1093                     clear();
1094                 }
1095             }
1096             updateStatsReturn(activeTime);
1097         }
1098     }
1099 
1100     /**
1101      * Sets the base pool configuration.
1102      *
1103      * @param conf the new configuration to use. This is used by value.
1104      * @see GenericObjectPoolConfig
1105      */
1106     public void setConfig(final GenericObjectPoolConfig<T> conf) {
1107         super.setConfig(conf);
1108         setMaxIdle(conf.getMaxIdle());
1109         setMinIdle(conf.getMinIdle());
1110         setMaxTotal(conf.getMaxTotal());
1111     }
1112 
1113     /**
1114      * Sets the cap on the number of "idle" instances in the pool. If maxIdle
1115      * is set too low on heavily loaded systems it is possible you will see
1116      * objects being destroyed and almost immediately new objects being created.
1117      * This is a result of the active threads momentarily returning objects
1118      * faster than they are requesting them, causing the number of idle
1119      * objects to rise above maxIdle. The best value for maxIdle for heavily
1120      * loaded system will vary but the default is a good starting point.
1121      *
1122      * @param maxIdle
1123      *            The cap on the number of "idle" instances in the pool. Use a
1124      *            negative value to indicate an unlimited number of idle
1125      *            instances
1126      * @see #getMaxIdle
1127      */
1128     public void setMaxIdle(final int maxIdle) {
1129         this.maxIdle = maxIdle;
1130     }
1131 
1132     /**
1133      * Sets the target for the minimum number of idle objects to maintain in
1134      * the pool. This setting only has an effect if it is positive and
1135      * {@link #getDurationBetweenEvictionRuns()} is greater than zero. If this
1136      * is the case, an attempt is made to ensure that the pool has the required
1137      * minimum number of instances during idle object eviction runs.
1138      * <p>
1139      * If the configured value of minIdle is greater than the configured value
1140      * for maxIdle then the value of maxIdle will be used instead.
1141      * </p>
1142      *
1143      * @param minIdle
1144      *            The minimum number of objects.
1145      * @see #getMinIdle()
1146      * @see #getMaxIdle()
1147      * @see #getDurationBetweenEvictionRuns()
1148      */
1149     public void setMinIdle(final int minIdle) {
1150         this.minIdle = minIdle;
1151     }
1152 
1153     @Override
1154     protected void toStringAppendFields(final StringBuilder builder) {
1155         super.toStringAppendFields(builder);
1156         builder.append(", factoryType=");
1157         builder.append(factoryType);
1158         builder.append(", maxIdle=");
1159         builder.append(maxIdle);
1160         builder.append(", minIdle=");
1161         builder.append(minIdle);
1162         builder.append(", factory=");
1163         builder.append(factory);
1164         builder.append(", allObjects=");
1165         builder.append(allObjects);
1166         builder.append(", createCount=");
1167         builder.append(createCount);
1168         builder.append(", idleObjects=");
1169         builder.append(idleObjects);
1170         builder.append(", abandonedConfig=");
1171         builder.append(abandonedConfig);
1172     }
1173 
1174     @Override
1175     public void use(final T pooledObject) {
1176         final AbandonedConfig abandonedCfg = this.abandonedConfig;
1177         if (abandonedCfg != null && abandonedCfg.getUseUsageTracking()) {
1178             final PooledObject<T> po = getPooledObject(pooledObject);
1179             if (po != null) {
1180                 po.use();
1181             }
1182         }
1183     }
1184 
1185 }