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