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}