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