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