Source code

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