001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.pool2.impl;
018
019import java.time.Duration;
020import java.time.Instant;
021import java.util.ArrayList;
022import java.util.NoSuchElementException;
023import java.util.Set;
024import java.util.concurrent.ConcurrentHashMap;
025import java.util.concurrent.atomic.AtomicLong;
026import java.util.stream.Collectors;
027
028import org.apache.commons.pool2.DestroyMode;
029import org.apache.commons.pool2.ObjectPool;
030import org.apache.commons.pool2.PoolUtils;
031import org.apache.commons.pool2.PooledObject;
032import org.apache.commons.pool2.PooledObjectFactory;
033import org.apache.commons.pool2.PooledObjectState;
034import org.apache.commons.pool2.SwallowedExceptionListener;
035import org.apache.commons.pool2.TrackedUse;
036import org.apache.commons.pool2.UsageTracking;
037
038/**
039 * A configurable {@link ObjectPool} implementation.
040 * <p>
041 * When coupled with the appropriate {@link PooledObjectFactory},
042 * {@code GenericObjectPool} provides robust pooling functionality for
043 * arbitrary objects.
044 * </p>
045 * <p>
046 * Optionally, one may configure the pool to examine and possibly evict objects
047 * as they sit idle in the pool and to ensure that a minimum number of idle
048 * objects are available. This is performed by an "idle object eviction" thread,
049 * which runs asynchronously. Caution should be used when configuring this
050 * optional feature. Eviction runs contend with client threads for access to
051 * objects in the pool, so if they run too frequently performance issues may
052 * result.
053 * </p>
054 * <p>
055 * The pool can also be configured to detect and remove "abandoned" objects,
056 * i.e. objects that have been checked out of the pool but neither used nor
057 * returned before the configured
058 * {@link AbandonedConfig#getRemoveAbandonedTimeoutDuration() removeAbandonedTimeout}.
059 * Abandoned object removal can be configured to happen when
060 * {@code borrowObject} is invoked and the pool is close to starvation, or
061 * it can be executed by the idle object evictor, or both. If pooled objects
062 * implement the {@link TrackedUse} interface, their last use will be queried
063 * using the {@code getLastUsed} method on that interface; otherwise
064 * abandonment is determined by how long an object has been checked out from
065 * the pool.
066 * </p>
067 * <p>
068 * Implementation note: To prevent possible deadlocks, care has been taken to
069 * ensure that no call to a factory method will occur within a synchronization
070 * block. See POOL-125 and DBCP-44 for more information.
071 * </p>
072 * <p>
073 * This class is intended to be thread-safe.
074 * </p>
075 *
076 * @see GenericKeyedObjectPool
077 *
078 * @param <T> Type of element pooled in this pool.
079 *
080 * @since 2.0
081 */
082public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
083        implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
084
085    // JMX specific attributes
086    private static final String ONAME_BASE =
087        "org.apache.commons.pool2:type=GenericObjectPool,name=";
088
089    private static void wait(final Object obj, final Duration duration) throws InterruptedException {
090        obj.wait(duration.toMillis(), duration.getNano() % 1_000_000);
091    }
092
093    private volatile String factoryType;
094
095    private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
096
097    private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
098
099    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}