    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}