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