You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/03/13 16:30:51 UTC
[commons-pool] branch master updated: Fix Javadoc nits.
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-pool.git
The following commit(s) were added to refs/heads/master by this push:
new be57d5a Fix Javadoc nits.
be57d5a is described below
commit be57d5ac62318fc9db1372a206b1b0c802d48616
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Mar 13 12:30:47 2019 -0400
Fix Javadoc nits.
---
.../commons/pool2/impl/GenericObjectPool.java | 2411 ++++++++++----------
1 file changed, 1214 insertions(+), 1197 deletions(-)
diff --git a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
index 7aff5f4..9158d3b 100644
--- a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
@@ -1,1197 +1,1214 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.pool2.impl;
-
-import org.apache.commons.pool2.ObjectPool;
-import org.apache.commons.pool2.PoolUtils;
-import org.apache.commons.pool2.PooledObject;
-import org.apache.commons.pool2.PooledObjectFactory;
-import org.apache.commons.pool2.PooledObjectState;
-import org.apache.commons.pool2.SwallowedExceptionListener;
-import org.apache.commons.pool2.TrackedUse;
-import org.apache.commons.pool2.UsageTracking;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * A configurable {@link ObjectPool} implementation.
- * <p>
- * When coupled with the appropriate {@link PooledObjectFactory},
- * <code>GenericObjectPool</code> provides robust pooling functionality for
- * arbitrary objects.</p>
- * <p>
- * Optionally, one may configure the pool to examine and possibly evict objects
- * as they sit idle in the pool and to ensure that a minimum number of idle
- * objects are available. This is performed by an "idle object eviction" thread,
- * which runs asynchronously. Caution should be used when configuring this
- * optional feature. Eviction runs contend with client threads for access to
- * objects in the pool, so if they run too frequently performance issues may
- * result.</p>
- * <p>
- * The pool can also be configured to detect and remove "abandoned" objects,
- * i.e. objects that have been checked out of the pool but neither used nor
- * returned before the configured
- * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}.
- * Abandoned object removal can be configured to happen when
- * <code>borrowObject</code> is invoked and the pool is close to starvation, or
- * it can be executed by the idle object evictor, or both. If pooled objects
- * implement the {@link TrackedUse} interface, their last use will be queried
- * using the <code>getLastUsed</code> method on that interface; otherwise
- * abandonment is determined by how long an object has been checked out from
- * the pool.</p>
- * <p>
- * Implementation note: To prevent possible deadlocks, care has been taken to
- * ensure that no call to a factory method will occur within a synchronization
- * block. See POOL-125 and DBCP-44 for more information.</p>
- * <p>
- * This class is intended to be thread-safe.</p>
- *
- * @see GenericKeyedObjectPool
- *
- * @param <T> Type of element pooled in this pool.
- *
- * @since 2.0
- */
-public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
- implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
-
- /**
- * Creates a new <code>GenericObjectPool</code> using defaults from
- * {@link GenericObjectPoolConfig}.
- *
- * @param factory The object factory to be used to create object instances
- * used by this pool
- */
- public GenericObjectPool(final PooledObjectFactory<T> factory) {
- this(factory, new GenericObjectPoolConfig<T>());
- }
-
- /**
- * Creates a new <code>GenericObjectPool</code> using a specific
- * configuration.
- *
- * @param factory The object factory to be used to create object instances
- * used by this pool
- * @param config The configuration to use for this pool instance. The
- * configuration is used by value. Subsequent changes to
- * the configuration object will not be reflected in the
- * pool.
- */
- public GenericObjectPool(final PooledObjectFactory<T> factory,
- final GenericObjectPoolConfig<T> config) {
-
- super(config, ONAME_BASE, config.getJmxNamePrefix());
-
- if (factory == null) {
- jmxUnregister(); // tidy up
- throw new IllegalArgumentException("factory may not be null");
- }
- this.factory = factory;
-
- idleObjects = new LinkedBlockingDeque<>(config.getFairness());
-
- setConfig(config);
- }
-
- /**
- * Creates a new <code>GenericObjectPool</code> that tracks and destroys
- * objects that are checked out, but never returned to the pool.
- *
- * @param factory The object factory to be used to create object instances
- * used by this pool
- * @param config The base pool configuration to use for this pool instance.
- * The configuration is used by value. Subsequent changes to
- * the configuration object will not be reflected in the
- * pool.
- * @param abandonedConfig Configuration for abandoned object identification
- * and removal. The configuration is used by value.
- */
- public GenericObjectPool(final PooledObjectFactory<T> factory,
- final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
- this(factory, config);
- setAbandonedConfig(abandonedConfig);
- }
-
- /**
- * Returns the cap on the number of "idle" instances in the pool. If maxIdle
- * is set too low on heavily loaded systems it is possible you will see
- * objects being destroyed and almost immediately new objects being created.
- * This is a result of the active threads momentarily returning objects
- * faster than they are requesting them, causing the number of idle
- * objects to rise above maxIdle. The best value for maxIdle for heavily
- * loaded system will vary but the default is a good starting point.
- *
- * @return the maximum number of "idle" instances that can be held in the
- * pool or a negative value if there is no limit
- *
- * @see #setMaxIdle
- */
- @Override
- public int getMaxIdle() {
- return maxIdle;
- }
-
- /**
- * Returns the cap on the number of "idle" instances in the pool. If maxIdle
- * is set too low on heavily loaded systems it is possible you will see
- * objects being destroyed and almost immediately new objects being created.
- * This is a result of the active threads momentarily returning objects
- * faster than they are requesting them, causing the number of idle
- * objects to rise above maxIdle. The best value for maxIdle for heavily
- * loaded system will vary but the default is a good starting point.
- *
- * @param maxIdle
- * The cap on the number of "idle" instances in the pool. Use a
- * negative value to indicate an unlimited number of idle
- * instances
- *
- * @see #getMaxIdle
- */
- public void setMaxIdle(final int maxIdle) {
- this.maxIdle = maxIdle;
- }
-
- /**
- * Sets the target for the minimum number of idle objects to maintain in
- * the pool. This setting only has an effect if it is positive and
- * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
- * is the case, an attempt is made to ensure that the pool has the required
- * minimum number of instances during idle object eviction runs.
- * <p>
- * If the configured value of minIdle is greater than the configured value
- * for maxIdle then the value of maxIdle will be used instead.
- *
- * @param minIdle
- * The minimum number of objects.
- *
- * @see #getMinIdle()
- * @see #getMaxIdle()
- * @see #getTimeBetweenEvictionRunsMillis()
- */
- public void setMinIdle(final int minIdle) {
- this.minIdle = minIdle;
- }
-
- /**
- * Returns the target for the minimum number of idle objects to maintain in
- * the pool. This setting only has an effect if it is positive and
- * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
- * is the case, an attempt is made to ensure that the pool has the required
- * minimum number of instances during idle object eviction runs.
- * <p>
- * If the configured value of minIdle is greater than the configured value
- * for maxIdle then the value of maxIdle will be used instead.
- *
- * @return The minimum number of objects.
- *
- * @see #setMinIdle(int)
- * @see #setMaxIdle(int)
- * @see #setTimeBetweenEvictionRunsMillis(long)
- */
- @Override
- public int getMinIdle() {
- final int maxIdleSave = getMaxIdle();
- if (this.minIdle > maxIdleSave) {
- return maxIdleSave;
- }
- return minIdle;
- }
-
- /**
- * Gets whether or not abandoned object removal is configured for this pool.
- *
- * @return true if this pool is configured to detect and remove
- * abandoned objects
- */
- @Override
- public boolean isAbandonedConfig() {
- return abandonedConfig != null;
- }
-
- /**
- * Gets whether this pool identifies and logs any abandoned objects.
- *
- * @return {@code true} if abandoned object removal is configured for this
- * pool and removal events are to be logged otherwise {@code false}
- *
- * @see AbandonedConfig#getLogAbandoned()
- */
- @Override
- public boolean getLogAbandoned() {
- final AbandonedConfig ac = this.abandonedConfig;
- return ac != null && ac.getLogAbandoned();
- }
-
- /**
- * Gets whether a check is made for abandoned objects when an object is borrowed
- * from this pool.
- *
- * @return {@code true} if abandoned object removal is configured to be
- * activated by borrowObject otherwise {@code false}
- *
- * @see AbandonedConfig#getRemoveAbandonedOnBorrow()
- */
- @Override
- public boolean getRemoveAbandonedOnBorrow() {
- final AbandonedConfig ac = this.abandonedConfig;
- return ac != null && ac.getRemoveAbandonedOnBorrow();
- }
-
- /**
- * Gets whether a check is made for abandoned objects when the evictor runs.
- *
- * @return {@code true} if abandoned object removal is configured to be
- * activated when the evictor runs otherwise {@code false}
- *
- * @see AbandonedConfig#getRemoveAbandonedOnMaintenance()
- */
- @Override
- public boolean getRemoveAbandonedOnMaintenance() {
- final AbandonedConfig ac = this.abandonedConfig;
- return ac != null && ac.getRemoveAbandonedOnMaintenance();
- }
-
- /**
- * Obtains the timeout before which an object will be considered to be
- * abandoned by this pool.
- *
- * @return The abandoned object timeout in seconds if abandoned object
- * removal is configured for this pool; Integer.MAX_VALUE otherwise.
- *
- * @see AbandonedConfig#getRemoveAbandonedTimeout()
- */
- @Override
- public int getRemoveAbandonedTimeout() {
- final AbandonedConfig ac = this.abandonedConfig;
- return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE;
- }
-
-
- /**
- * Sets the base pool configuration.
- *
- * @param conf the new configuration to use. This is used by value.
- *
- * @see GenericObjectPoolConfig
- */
- public void setConfig(final GenericObjectPoolConfig<T> conf) {
- super.setConfig(conf);
- setMaxIdle(conf.getMaxIdle());
- setMinIdle(conf.getMinIdle());
- setMaxTotal(conf.getMaxTotal());
- }
-
- /**
- * Sets the abandoned object removal configuration.
- *
- * @param abandonedConfig the new configuration to use. This is used by value.
- *
- * @see AbandonedConfig
- */
- public void setAbandonedConfig(final AbandonedConfig abandonedConfig) {
- if (abandonedConfig == null) {
- this.abandonedConfig = null;
- } else {
- this.abandonedConfig = new AbandonedConfig();
- this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned());
- this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter());
- this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
- this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance());
- this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeout());
- this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
- this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace());
- }
- }
-
- /**
- * Obtains a reference to the factory used to create, destroy and validate
- * the objects used by this pool.
- *
- * @return the factory
- */
- public PooledObjectFactory<T> getFactory() {
- return factory;
- }
-
- /**
- * Equivalent to <code>{@link #borrowObject(long)
- * borrowObject}({@link #getMaxWaitMillis()})</code>.
- * <p>
- * {@inheritDoc}
- */
- @Override
- public T borrowObject() throws Exception {
- return borrowObject(getMaxWaitMillis());
- }
-
- /**
- * Borrows an object from the pool using the specific waiting time which only
- * applies if {@link #getBlockWhenExhausted()} is true.
- * <p>
- * If there is one or more idle instance available in the pool, then an
- * idle instance will be selected based on the value of {@link #getLifo()},
- * activated and returned. If activation fails, or {@link #getTestOnBorrow()
- * testOnBorrow} is set to <code>true</code> and validation fails, the
- * instance is destroyed and the next available instance is examined. This
- * continues until either a valid instance is returned or there are no more
- * idle instances available.
- * <p>
- * If there are no idle instances available in the pool, behavior depends on
- * the {@link #getMaxTotal() maxTotal}, (if applicable)
- * {@link #getBlockWhenExhausted()} and the value passed in to the
- * <code>borrowMaxWaitMillis</code> parameter. If the number of instances
- * checked out from the pool is less than <code>maxTotal,</code> a new
- * instance is created, activated and (if applicable) validated and returned
- * to the caller. If validation fails, a <code>NoSuchElementException</code>
- * is thrown.
- * <p>
- * If the pool is exhausted (no available idle instances and no capacity to
- * create new ones), this method will either block (if
- * {@link #getBlockWhenExhausted()} is true) or throw a
- * <code>NoSuchElementException</code> (if
- * {@link #getBlockWhenExhausted()} is false). The length of time that this
- * method will block when {@link #getBlockWhenExhausted()} is true is
- * determined by the value passed in to the <code>borrowMaxWaitMillis</code>
- * parameter.
- * <p>
- * When the pool is exhausted, multiple calling threads may be
- * simultaneously blocked waiting for instances to become available. A
- * "fairness" algorithm has been implemented to ensure that threads receive
- * available instances in request arrival order.
- *
- * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
- * to become available
- *
- * @return object instance from the pool
- *
- * @throws NoSuchElementException if an instance cannot be returned
- *
- * @throws Exception if an object instance cannot be returned due to an
- * error
- */
- public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
- assertOpen();
-
- final AbandonedConfig ac = this.abandonedConfig;
- if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
- (getNumIdle() < 2) &&
- (getNumActive() > getMaxTotal() - 3) ) {
- removeAbandoned(ac);
- }
-
- PooledObject<T> p = null;
-
- // Get local copy of current config so it is consistent for entire
- // method execution
- final boolean blockWhenExhausted = getBlockWhenExhausted();
-
- boolean create;
- final long waitTime = System.currentTimeMillis();
-
- while (p == null) {
- create = false;
- p = idleObjects.pollFirst();
- if (p == null) {
- p = create();
- if (p != null) {
- create = true;
- }
- }
- if (blockWhenExhausted) {
- if (p == null) {
- if (borrowMaxWaitMillis < 0) {
- p = idleObjects.takeFirst();
- } else {
- p = idleObjects.pollFirst(borrowMaxWaitMillis,
- TimeUnit.MILLISECONDS);
- }
- }
- if (p == null) {
- throw new NoSuchElementException(
- "Timeout waiting for idle object");
- }
- } else {
- if (p == null) {
- throw new NoSuchElementException("Pool exhausted");
- }
- }
- if (!p.allocate()) {
- p = null;
- }
-
- if (p != null) {
- try {
- factory.activateObject(p);
- } catch (final Exception e) {
- try {
- destroy(p);
- } catch (final Exception e1) {
- // Ignore - activation failure is more important
- }
- p = null;
- if (create) {
- final NoSuchElementException nsee = new NoSuchElementException(
- "Unable to activate object");
- nsee.initCause(e);
- throw nsee;
- }
- }
- if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
- boolean validate = false;
- Throwable validationThrowable = null;
- try {
- validate = factory.validateObject(p);
- } catch (final Throwable t) {
- PoolUtils.checkRethrow(t);
- validationThrowable = t;
- }
- if (!validate) {
- try {
- destroy(p);
- destroyedByBorrowValidationCount.incrementAndGet();
- } catch (final Exception e) {
- // Ignore - validation failure is more important
- }
- p = null;
- if (create) {
- final NoSuchElementException nsee = new NoSuchElementException(
- "Unable to validate object");
- nsee.initCause(validationThrowable);
- throw nsee;
- }
- }
- }
- }
- }
-
- updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
-
- return p.getObject();
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * If {@link #getMaxIdle() maxIdle} is set to a positive value and the
- * number of idle instances has reached this value, the returning instance
- * is destroyed.
- * <p>
- * If {@link #getTestOnReturn() testOnReturn} == true, the returning
- * instance is validated before being returned to the idle instance pool. In
- * this case, if validation fails, the instance is destroyed.
- * <p>
- * Exceptions encountered destroying objects for any reason are swallowed
- * but notified via a {@link SwallowedExceptionListener}.
- */
- @Override
- public void returnObject(final T obj) {
- final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
-
- if (p == null) {
- if (!isAbandonedConfig()) {
- throw new IllegalStateException(
- "Returned object not currently part of this pool");
- }
- return; // Object was abandoned and removed
- }
-
- markReturningState(p);
-
- final long activeTime = p.getActiveTimeMillis();
-
- if (getTestOnReturn() && !factory.validateObject(p)) {
- try {
- destroy(p);
- } catch (final Exception e) {
- swallowException(e);
- }
- try {
- ensureIdle(1, false);
- } catch (final Exception e) {
- swallowException(e);
- }
- updateStatsReturn(activeTime);
- return;
- }
-
- try {
- factory.passivateObject(p);
- } catch (final Exception e1) {
- swallowException(e1);
- try {
- destroy(p);
- } catch (final Exception e) {
- swallowException(e);
- }
- try {
- ensureIdle(1, false);
- } catch (final Exception e) {
- swallowException(e);
- }
- updateStatsReturn(activeTime);
- return;
- }
-
- if (!p.deallocate()) {
- throw new IllegalStateException(
- "Object has already been returned to this pool or is invalid");
- }
-
- final int maxIdleSave = getMaxIdle();
- if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
- try {
- destroy(p);
- } catch (final Exception e) {
- swallowException(e);
- }
- } else {
- if (getLifo()) {
- idleObjects.addFirst(p);
- } else {
- idleObjects.addLast(p);
- }
- if (isClosed()) {
- // Pool closed while object was being added to idle objects.
- // Make sure the returned object is destroyed rather than left
- // in the idle object pool (which would effectively be a leak)
- clear();
- }
- }
- updateStatsReturn(activeTime);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Activation of this method decrements the active count and attempts to
- * destroy the instance.
- *
- * @throws Exception if an exception occurs destroying the
- * object
- * @throws IllegalStateException if obj does not belong to this pool
- */
- @Override
- public void invalidateObject(final T obj) throws Exception {
- final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
- if (p == null) {
- if (isAbandonedConfig()) {
- return;
- }
- throw new IllegalStateException(
- "Invalidated object not currently part of this pool");
- }
- synchronized (p) {
- if (p.getState() != PooledObjectState.INVALID) {
- destroy(p);
- }
- }
- ensureIdle(1, false);
- }
-
- /**
- * Clears any objects sitting idle in the pool by removing them from the
- * idle instance pool and then invoking the configured
- * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each
- * idle instance.
- * <p>
- * Implementation notes:
- * <ul>
- * <li>This method does not destroy or effect in any way instances that are
- * checked out of the pool when it is invoked.</li>
- * <li>Invoking this method does not prevent objects being returned to the
- * idle instance pool, even during its execution. Additional instances may
- * be returned while removed items are being destroyed.</li>
- * <li>Exceptions encountered destroying idle instances are swallowed
- * but notified via a {@link SwallowedExceptionListener}.</li>
- * </ul>
- */
- @Override
- public void clear() {
- PooledObject<T> p = idleObjects.poll();
-
- while (p != null) {
- try {
- destroy(p);
- } catch (final Exception e) {
- swallowException(e);
- }
- p = idleObjects.poll();
- }
- }
-
- @Override
- public int getNumActive() {
- return allObjects.size() - idleObjects.size();
- }
-
- @Override
- public int getNumIdle() {
- return idleObjects.size();
- }
-
- /**
- * Closes the pool. Once the pool is closed, {@link #borrowObject()} will
- * fail with IllegalStateException, but {@link #returnObject(Object)} and
- * {@link #invalidateObject(Object)} will continue to work, with returned
- * objects destroyed on return.
- * <p>
- * Destroys idle instances in the pool by invoking {@link #clear()}.
- */
- @Override
- public void close() {
- if (isClosed()) {
- return;
- }
-
- synchronized (closeLock) {
- if (isClosed()) {
- return;
- }
-
- // Stop the evictor before the pool is closed since evict() calls
- // assertOpen()
- stopEvitor();
-
- closed = true;
- // This clear removes any idle objects
- clear();
-
- jmxUnregister();
-
- // Release any threads that were waiting for an object
- idleObjects.interuptTakeWaiters();
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Successive activations of this method examine objects in sequence,
- * cycling through objects in oldest-to-youngest order.
- */
- @Override
- public void evict() throws Exception {
- assertOpen();
-
- if (idleObjects.size() > 0) {
-
- PooledObject<T> underTest = null;
- final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
-
- synchronized (evictionLock) {
- final EvictionConfig evictionConfig = new EvictionConfig(
- getMinEvictableIdleTimeMillis(),
- getSoftMinEvictableIdleTimeMillis(),
- getMinIdle());
-
- final boolean testWhileIdle = getTestWhileIdle();
-
- for (int i = 0, m = getNumTests(); i < m; i++) {
- if (evictionIterator == null || !evictionIterator.hasNext()) {
- evictionIterator = new EvictionIterator(idleObjects);
- }
- if (!evictionIterator.hasNext()) {
- // Pool exhausted, nothing to do here
- return;
- }
-
- try {
- underTest = evictionIterator.next();
- } catch (final NoSuchElementException nsee) {
- // Object was borrowed in another thread
- // Don't count this as an eviction test so reduce i;
- i--;
- evictionIterator = null;
- continue;
- }
-
- if (!underTest.startEvictionTest()) {
- // Object was borrowed in another thread
- // Don't count this as an eviction test so reduce i;
- i--;
- continue;
- }
-
- // User provided eviction policy could throw all sorts of
- // crazy exceptions. Protect against such an exception
- // killing the eviction thread.
- boolean evict;
- try {
- evict = evictionPolicy.evict(evictionConfig, underTest,
- idleObjects.size());
- } catch (final Throwable t) {
- // Slightly convoluted as SwallowedExceptionListener
- // uses Exception rather than Throwable
- PoolUtils.checkRethrow(t);
- swallowException(new Exception(t));
- // Don't evict on error conditions
- evict = false;
- }
-
- if (evict) {
- destroy(underTest);
- destroyedByEvictorCount.incrementAndGet();
- } else {
- if (testWhileIdle) {
- boolean active = false;
- try {
- factory.activateObject(underTest);
- active = true;
- } catch (final Exception e) {
- destroy(underTest);
- destroyedByEvictorCount.incrementAndGet();
- }
- if (active) {
- if (!factory.validateObject(underTest)) {
- destroy(underTest);
- destroyedByEvictorCount.incrementAndGet();
- } else {
- try {
- factory.passivateObject(underTest);
- } catch (final Exception e) {
- destroy(underTest);
- destroyedByEvictorCount.incrementAndGet();
- }
- }
- }
- }
- if (!underTest.endEvictionTest(idleObjects)) {
- // TODO - May need to add code here once additional
- // states are used
- }
- }
- }
- }
- }
- final AbandonedConfig ac = this.abandonedConfig;
- if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
- removeAbandoned(ac);
- }
- }
-
- /**
- * Tries to ensure that {@link #getMinIdle()} idle instances are available
- * in the pool.
- *
- * @throws Exception If the associated factory throws an exception
- * @since 2.4
- */
- public void preparePool() throws Exception {
- if (getMinIdle() < 1) {
- return;
- }
- ensureMinIdle();
- }
-
- /**
- * Attempts to create a new wrapped pooled object.
- * <p>
- * If there are {@link #getMaxTotal()} objects already in circulation
- * or in process of being created, this method returns null.
- *
- * @return The new wrapped pooled object
- *
- * @throws Exception if the object factory's {@code makeObject} fails
- */
- private PooledObject<T> create() throws Exception {
- int localMaxTotal = getMaxTotal();
- // This simplifies the code later in this method
- if (localMaxTotal < 0) {
- localMaxTotal = Integer.MAX_VALUE;
- }
-
- final long localStartTimeMillis = System.currentTimeMillis();
- final long localMaxWaitTimeMillis = Math.max(getMaxWaitMillis(), 0);
-
- // Flag that indicates if create should:
- // - TRUE: call the factory to create an object
- // - FALSE: return null
- // - null: loop and re-test the condition that determines whether to
- // call the factory
- Boolean create = null;
- while (create == null) {
- synchronized (makeObjectCountLock) {
- final long newCreateCount = createCount.incrementAndGet();
- if (newCreateCount > localMaxTotal) {
- // The pool is currently at capacity or in the process of
- // making enough new objects to take it to capacity.
- createCount.decrementAndGet();
- if (makeObjectCount == 0) {
- // There are no makeObject() calls in progress so the
- // pool is at capacity. Do not attempt to create a new
- // object. Return and wait for an object to be returned
- create = Boolean.FALSE;
- } else {
- // There are makeObject() calls in progress that might
- // bring the pool to capacity. Those calls might also
- // fail so wait until they complete and then re-test if
- // the pool is at capacity or not.
- makeObjectCountLock.wait(localMaxWaitTimeMillis);
- }
- } else {
- // The pool is not at capacity. Create a new object.
- makeObjectCount++;
- create = Boolean.TRUE;
- }
- }
-
- // Do not block more if maxWaitTimeMillis is set.
- if (create == null &&
- (localMaxWaitTimeMillis > 0 &&
- System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) {
- create = Boolean.FALSE;
- }
- }
-
- if (!create.booleanValue()) {
- return null;
- }
-
- final PooledObject<T> p;
- try {
- p = factory.makeObject();
- } catch (final Throwable e) {
- createCount.decrementAndGet();
- throw e;
- } finally {
- synchronized (makeObjectCountLock) {
- makeObjectCount--;
- makeObjectCountLock.notifyAll();
- }
- }
-
- final AbandonedConfig ac = this.abandonedConfig;
- if (ac != null && ac.getLogAbandoned()) {
- p.setLogAbandoned(true);
- // TODO: in 3.0, this can use the method defined on PooledObject
- if (p instanceof DefaultPooledObject<?>) {
- ((DefaultPooledObject<T>) p).setRequireFullStackTrace(ac.getRequireFullStackTrace());
- }
- }
-
- createdCount.incrementAndGet();
- allObjects.put(new IdentityWrapper<>(p.getObject()), p);
- return p;
- }
-
- /**
- * Destroys a wrapped pooled object.
- *
- * @param toDestroy The wrapped pooled object to destroy
- *
- * @throws Exception If the factory fails to destroy the pooled object
- * cleanly
- */
- private void destroy(final PooledObject<T> toDestroy) throws Exception {
- toDestroy.invalidate();
- idleObjects.remove(toDestroy);
- allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
- try {
- factory.destroyObject(toDestroy);
- } finally {
- destroyedCount.incrementAndGet();
- createCount.decrementAndGet();
- }
-
- if (idleObjects.isEmpty() && idleObjects.hasTakeWaiters()) {
- // POOL-356.
- // In case there are already threads waiting on something in the pool
- // (e.g. idleObjects.takeFirst(); then we need to provide them a fresh instance.
- // Otherwise they will be stuck forever (or until timeout)
- final PooledObject<T> freshPooled = create();
- idleObjects.put(freshPooled);
- }
- }
-
- @Override
- void ensureMinIdle() throws Exception {
- ensureIdle(getMinIdle(), true);
- }
-
- /**
- * Tries to ensure that {@code idleCount} idle instances exist in the pool.
- * <p>
- * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount}
- * or the total number of objects (idle, checked out, or being created) reaches
- * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless
- * there are threads waiting to check out instances from the pool.
- *
- * @param idleCount the number of idle instances desired
- * @param always true means create instances even if the pool has no threads waiting
- * @throws Exception if the factory's makeObject throws
- */
- private void ensureIdle(final int idleCount, final boolean always) throws Exception {
- if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
- return;
- }
-
- while (idleObjects.size() < idleCount) {
- final PooledObject<T> p = create();
- if (p == null) {
- // Can't create objects, no reason to think another call to
- // create will work. Give up.
- break;
- }
- if (getLifo()) {
- idleObjects.addFirst(p);
- } else {
- idleObjects.addLast(p);
- }
- }
- if (isClosed()) {
- // Pool closed while object was being added to idle objects.
- // Make sure the returned object is destroyed rather than left
- // in the idle object pool (which would effectively be a leak)
- clear();
- }
- }
-
- /**
- * Creates an object, and place it into the pool. addObject() is useful for
- * "pre-loading" a pool with idle objects.
- * <p>
- * If there is no capacity available to add to the pool, this is a no-op
- * (no exception, no impact to the pool). </p>
- */
- @Override
- public void addObject() throws Exception {
- assertOpen();
- if (factory == null) {
- throw new IllegalStateException(
- "Cannot add objects without a factory.");
- }
- final PooledObject<T> p = create();
- addIdleObject(p);
- }
-
- /**
- * Adds the provided wrapped pooled object to the set of idle objects for
- * this pool. The object must already be part of the pool. If {@code p}
- * is null, this is a no-op (no exception, but no impact on the pool).
- *
- * @param p The object to make idle
- *
- * @throws Exception If the factory fails to passivate the object
- */
- private void addIdleObject(final PooledObject<T> p) throws Exception {
- if (p != null) {
- factory.passivateObject(p);
- if (getLifo()) {
- idleObjects.addFirst(p);
- } else {
- idleObjects.addLast(p);
- }
- }
- }
-
- /**
- * Calculates the number of objects to test in a run of the idle object
- * evictor.
- *
- * @return The number of objects to test for validity
- */
- private int getNumTests() {
- final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
- if (numTestsPerEvictionRun >= 0) {
- return Math.min(numTestsPerEvictionRun, idleObjects.size());
- }
- return (int) (Math.ceil(idleObjects.size() /
- Math.abs((double) numTestsPerEvictionRun)));
- }
-
- /**
- * Recovers abandoned objects which have been checked out but
- * not used since longer than the removeAbandonedTimeout.
- *
- * @param ac The configuration to use to identify abandoned objects
- */
- private void removeAbandoned(final AbandonedConfig ac) {
- // Generate a list of abandoned objects to remove
- final long now = System.currentTimeMillis();
- final long timeout =
- now - (ac.getRemoveAbandonedTimeout() * 1000L);
- final ArrayList<PooledObject<T>> remove = new ArrayList<>();
- final Iterator<PooledObject<T>> it = allObjects.values().iterator();
- while (it.hasNext()) {
- final PooledObject<T> pooledObject = it.next();
- synchronized (pooledObject) {
- if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
- pooledObject.getLastUsedTime() <= timeout) {
- pooledObject.markAbandoned();
- remove.add(pooledObject);
- }
- }
- }
-
- // Now remove the abandoned objects
- final Iterator<PooledObject<T>> itr = remove.iterator();
- while (itr.hasNext()) {
- final PooledObject<T> pooledObject = itr.next();
- if (ac.getLogAbandoned()) {
- pooledObject.printStackTrace(ac.getLogWriter());
- }
- try {
- invalidateObject(pooledObject.getObject());
- } catch (final Exception e) {
- e.printStackTrace();
- }
- }
- }
-
-
- //--- Usage tracking support -----------------------------------------------
-
- @Override
- public void use(final T pooledObject) {
- final AbandonedConfig ac = this.abandonedConfig;
- if (ac != null && ac.getUseUsageTracking()) {
- final PooledObject<T> wrapper = allObjects.get(new IdentityWrapper<>(pooledObject));
- wrapper.use();
- }
- }
-
-
- //--- JMX support ----------------------------------------------------------
-
- private volatile String factoryType = null;
-
- /**
- * Returns an estimate of the number of threads currently blocked waiting for
- * an object from the pool. This is intended for monitoring only, not for
- * synchronization control.
- *
- * @return The estimate of the number of threads currently blocked waiting
- * for an object from the pool
- */
- @Override
- public int getNumWaiters() {
- if (getBlockWhenExhausted()) {
- return idleObjects.getTakeQueueLength();
- }
- return 0;
- }
-
- /**
- * Returns the type - including the specific type rather than the generic -
- * of the factory.
- *
- * @return A string representation of the factory type
- */
- @Override
- public String getFactoryType() {
- // Not thread safe. Accept that there may be multiple evaluations.
- if (factoryType == null) {
- final StringBuilder result = new StringBuilder();
- result.append(factory.getClass().getName());
- result.append('<');
- final Class<?> pooledObjectType =
- PoolImplUtils.getFactoryType(factory.getClass());
- result.append(pooledObjectType.getName());
- result.append('>');
- factoryType = result.toString();
- }
- return factoryType;
- }
-
- /**
- * Provides information on all the objects in the pool, both idle (waiting
- * to be borrowed) and active (currently borrowed).
- * <p>
- * Note: This is named listAllObjects so it is presented as an operation via
- * JMX. That means it won't be invoked unless the explicitly requested
- * whereas all attributes will be automatically requested when viewing the
- * attributes for an object in a tool like JConsole.
- *
- * @return Information grouped on all the objects in the pool
- */
- @Override
- public Set<DefaultPooledObjectInfo> listAllObjects() {
- final Set<DefaultPooledObjectInfo> result =
- new HashSet<>(allObjects.size());
- for (final PooledObject<T> p : allObjects.values()) {
- result.add(new DefaultPooledObjectInfo(p));
- }
- return result;
- }
-
- // --- configuration attributes --------------------------------------------
-
- private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
- private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
- private final PooledObjectFactory<T> factory;
-
-
- // --- internal attributes -------------------------------------------------
-
- /*
- * All of the objects currently associated with this pool in any state. It
- * excludes objects that have been destroyed. The size of
- * {@link #allObjects} will always be less than or equal to {@link
- * #_maxActive}. Map keys are pooled objects, values are the PooledObject
- * wrappers used internally by the pool.
- */
- private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
- new ConcurrentHashMap<>();
- /*
- * The combined count of the currently created objects and those in the
- * process of being created. Under load, it may exceed {@link #_maxActive}
- * if multiple threads try and create a new object at the same time but
- * {@link #create()} will ensure that there are never more than
- * {@link #_maxActive} objects created at any one time.
- */
- private final AtomicLong createCount = new AtomicLong(0);
- private long makeObjectCount = 0;
- private final Object makeObjectCountLock = new Object();
- private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
-
- // JMX specific attributes
- private static final String ONAME_BASE =
- "org.apache.commons.pool2:type=GenericObjectPool,name=";
-
- // Additional configuration properties for abandoned object tracking
- private volatile AbandonedConfig abandonedConfig = null;
-
- @Override
- protected void toStringAppendFields(final StringBuilder builder) {
- super.toStringAppendFields(builder);
- builder.append(", factoryType=");
- builder.append(factoryType);
- builder.append(", maxIdle=");
- builder.append(maxIdle);
- builder.append(", minIdle=");
- builder.append(minIdle);
- builder.append(", factory=");
- builder.append(factory);
- builder.append(", allObjects=");
- builder.append(allObjects);
- builder.append(", createCount=");
- builder.append(createCount);
- builder.append(", idleObjects=");
- builder.append(idleObjects);
- builder.append(", abandonedConfig=");
- builder.append(abandonedConfig);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.pool2.impl;
+
+import org.apache.commons.pool2.ObjectPool;
+import org.apache.commons.pool2.PoolUtils;
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.PooledObjectFactory;
+import org.apache.commons.pool2.PooledObjectState;
+import org.apache.commons.pool2.SwallowedExceptionListener;
+import org.apache.commons.pool2.TrackedUse;
+import org.apache.commons.pool2.UsageTracking;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A configurable {@link ObjectPool} implementation.
+ * <p>
+ * When coupled with the appropriate {@link PooledObjectFactory},
+ * <code>GenericObjectPool</code> provides robust pooling functionality for
+ * arbitrary objects.</p>
+ * <p>
+ * Optionally, one may configure the pool to examine and possibly evict objects
+ * as they sit idle in the pool and to ensure that a minimum number of idle
+ * objects are available. This is performed by an "idle object eviction" thread,
+ * which runs asynchronously. Caution should be used when configuring this
+ * optional feature. Eviction runs contend with client threads for access to
+ * objects in the pool, so if they run too frequently performance issues may
+ * result.</p>
+ * <p>
+ * The pool can also be configured to detect and remove "abandoned" objects,
+ * i.e. objects that have been checked out of the pool but neither used nor
+ * returned before the configured
+ * {@link AbandonedConfig#getRemoveAbandonedTimeout() removeAbandonedTimeout}.
+ * Abandoned object removal can be configured to happen when
+ * <code>borrowObject</code> is invoked and the pool is close to starvation, or
+ * it can be executed by the idle object evictor, or both. If pooled objects
+ * implement the {@link TrackedUse} interface, their last use will be queried
+ * using the <code>getLastUsed</code> method on that interface; otherwise
+ * abandonment is determined by how long an object has been checked out from
+ * the pool.</p>
+ * <p>
+ * Implementation note: To prevent possible deadlocks, care has been taken to
+ * ensure that no call to a factory method will occur within a synchronization
+ * block. See POOL-125 and DBCP-44 for more information.</p>
+ * <p>
+ * This class is intended to be thread-safe.</p>
+ *
+ * @see GenericKeyedObjectPool
+ *
+ * @param <T> Type of element pooled in this pool.
+ *
+ * @since 2.0
+ */
+public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
+ implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {
+
+ /**
+ * Creates a new <code>GenericObjectPool</code> using defaults from
+ * {@link GenericObjectPoolConfig}.
+ *
+ * @param factory The object factory to be used to create object instances
+ * used by this pool
+ */
+ public GenericObjectPool(final PooledObjectFactory<T> factory) {
+ this(factory, new GenericObjectPoolConfig<T>());
+ }
+
+ /**
+ * Creates a new <code>GenericObjectPool</code> using a specific
+ * configuration.
+ *
+ * @param factory The object factory to be used to create object instances
+ * used by this pool
+ * @param config The configuration to use for this pool instance. The
+ * configuration is used by value. Subsequent changes to
+ * the configuration object will not be reflected in the
+ * pool.
+ */
+ public GenericObjectPool(final PooledObjectFactory<T> factory,
+ final GenericObjectPoolConfig<T> config) {
+
+ super(config, ONAME_BASE, config.getJmxNamePrefix());
+
+ if (factory == null) {
+ jmxUnregister(); // tidy up
+ throw new IllegalArgumentException("factory may not be null");
+ }
+ this.factory = factory;
+
+ idleObjects = new LinkedBlockingDeque<>(config.getFairness());
+
+ setConfig(config);
+ }
+
+ /**
+ * Creates a new <code>GenericObjectPool</code> that tracks and destroys
+ * objects that are checked out, but never returned to the pool.
+ *
+ * @param factory The object factory to be used to create object instances
+ * used by this pool
+ * @param config The base pool configuration to use for this pool instance.
+ * The configuration is used by value. Subsequent changes to
+ * the configuration object will not be reflected in the
+ * pool.
+ * @param abandonedConfig Configuration for abandoned object identification
+ * and removal. The configuration is used by value.
+ */
+ public GenericObjectPool(final PooledObjectFactory<T> factory,
+ final GenericObjectPoolConfig<T> config, final AbandonedConfig abandonedConfig) {
+ this(factory, config);
+ setAbandonedConfig(abandonedConfig);
+ }
+
+ /**
+ * Returns the cap on the number of "idle" instances in the pool. If maxIdle
+ * is set too low on heavily loaded systems it is possible you will see
+ * objects being destroyed and almost immediately new objects being created.
+ * This is a result of the active threads momentarily returning objects
+ * faster than they are requesting them, causing the number of idle
+ * objects to rise above maxIdle. The best value for maxIdle for heavily
+ * loaded system will vary but the default is a good starting point.
+ *
+ * @return the maximum number of "idle" instances that can be held in the
+ * pool or a negative value if there is no limit
+ *
+ * @see #setMaxIdle
+ */
+ @Override
+ public int getMaxIdle() {
+ return maxIdle;
+ }
+
+ /**
+ * Returns the cap on the number of "idle" instances in the pool. If maxIdle
+ * is set too low on heavily loaded systems it is possible you will see
+ * objects being destroyed and almost immediately new objects being created.
+ * This is a result of the active threads momentarily returning objects
+ * faster than they are requesting them, causing the number of idle
+ * objects to rise above maxIdle. The best value for maxIdle for heavily
+ * loaded system will vary but the default is a good starting point.
+ *
+ * @param maxIdle
+ * The cap on the number of "idle" instances in the pool. Use a
+ * negative value to indicate an unlimited number of idle
+ * instances
+ *
+ * @see #getMaxIdle
+ */
+ public void setMaxIdle(final int maxIdle) {
+ this.maxIdle = maxIdle;
+ }
+
+ /**
+ * Sets the target for the minimum number of idle objects to maintain in
+ * the pool. This setting only has an effect if it is positive and
+ * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
+ * is the case, an attempt is made to ensure that the pool has the required
+ * minimum number of instances during idle object eviction runs.
+ * <p>
+ * If the configured value of minIdle is greater than the configured value
+ * for maxIdle then the value of maxIdle will be used instead.
+ * </p>
+ *
+ * @param minIdle
+ * The minimum number of objects.
+ *
+ * @see #getMinIdle()
+ * @see #getMaxIdle()
+ * @see #getTimeBetweenEvictionRunsMillis()
+ */
+ public void setMinIdle(final int minIdle) {
+ this.minIdle = minIdle;
+ }
+
+ /**
+ * Returns the target for the minimum number of idle objects to maintain in
+ * the pool. This setting only has an effect if it is positive and
+ * {@link #getTimeBetweenEvictionRunsMillis()} is greater than zero. If this
+ * is the case, an attempt is made to ensure that the pool has the required
+ * minimum number of instances during idle object eviction runs.
+ * <p>
+ * If the configured value of minIdle is greater than the configured value
+ * for maxIdle then the value of maxIdle will be used instead.
+ * </p>
+ *
+ * @return The minimum number of objects.
+ *
+ * @see #setMinIdle(int)
+ * @see #setMaxIdle(int)
+ * @see #setTimeBetweenEvictionRunsMillis(long)
+ */
+ @Override
+ public int getMinIdle() {
+ final int maxIdleSave = getMaxIdle();
+ if (this.minIdle > maxIdleSave) {
+ return maxIdleSave;
+ }
+ return minIdle;
+ }
+
+ /**
+ * Gets whether or not abandoned object removal is configured for this pool.
+ *
+ * @return true if this pool is configured to detect and remove
+ * abandoned objects
+ */
+ @Override
+ public boolean isAbandonedConfig() {
+ return abandonedConfig != null;
+ }
+
+ /**
+ * Gets whether this pool identifies and logs any abandoned objects.
+ *
+ * @return {@code true} if abandoned object removal is configured for this
+ * pool and removal events are to be logged otherwise {@code false}
+ *
+ * @see AbandonedConfig#getLogAbandoned()
+ */
+ @Override
+ public boolean getLogAbandoned() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null && ac.getLogAbandoned();
+ }
+
+ /**
+ * Gets whether a check is made for abandoned objects when an object is borrowed
+ * from this pool.
+ *
+ * @return {@code true} if abandoned object removal is configured to be
+ * activated by borrowObject otherwise {@code false}
+ *
+ * @see AbandonedConfig#getRemoveAbandonedOnBorrow()
+ */
+ @Override
+ public boolean getRemoveAbandonedOnBorrow() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null && ac.getRemoveAbandonedOnBorrow();
+ }
+
+ /**
+ * Gets whether a check is made for abandoned objects when the evictor runs.
+ *
+ * @return {@code true} if abandoned object removal is configured to be
+ * activated when the evictor runs otherwise {@code false}
+ *
+ * @see AbandonedConfig#getRemoveAbandonedOnMaintenance()
+ */
+ @Override
+ public boolean getRemoveAbandonedOnMaintenance() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null && ac.getRemoveAbandonedOnMaintenance();
+ }
+
+ /**
+ * Obtains the timeout before which an object will be considered to be
+ * abandoned by this pool.
+ *
+ * @return The abandoned object timeout in seconds if abandoned object
+ * removal is configured for this pool; Integer.MAX_VALUE otherwise.
+ *
+ * @see AbandonedConfig#getRemoveAbandonedTimeout()
+ */
+ @Override
+ public int getRemoveAbandonedTimeout() {
+ final AbandonedConfig ac = this.abandonedConfig;
+ return ac != null ? ac.getRemoveAbandonedTimeout() : Integer.MAX_VALUE;
+ }
+
+
+ /**
+ * Sets the base pool configuration.
+ *
+ * @param conf the new configuration to use. This is used by value.
+ *
+ * @see GenericObjectPoolConfig
+ */
+ public void setConfig(final GenericObjectPoolConfig<T> conf) {
+ super.setConfig(conf);
+ setMaxIdle(conf.getMaxIdle());
+ setMinIdle(conf.getMinIdle());
+ setMaxTotal(conf.getMaxTotal());
+ }
+
+ /**
+ * Sets the abandoned object removal configuration.
+ *
+ * @param abandonedConfig the new configuration to use. This is used by value.
+ *
+ * @see AbandonedConfig
+ */
+ public void setAbandonedConfig(final AbandonedConfig abandonedConfig) {
+ if (abandonedConfig == null) {
+ this.abandonedConfig = null;
+ } else {
+ this.abandonedConfig = new AbandonedConfig();
+ this.abandonedConfig.setLogAbandoned(abandonedConfig.getLogAbandoned());
+ this.abandonedConfig.setLogWriter(abandonedConfig.getLogWriter());
+ this.abandonedConfig.setRemoveAbandonedOnBorrow(abandonedConfig.getRemoveAbandonedOnBorrow());
+ this.abandonedConfig.setRemoveAbandonedOnMaintenance(abandonedConfig.getRemoveAbandonedOnMaintenance());
+ this.abandonedConfig.setRemoveAbandonedTimeout(abandonedConfig.getRemoveAbandonedTimeout());
+ this.abandonedConfig.setUseUsageTracking(abandonedConfig.getUseUsageTracking());
+ this.abandonedConfig.setRequireFullStackTrace(abandonedConfig.getRequireFullStackTrace());
+ }
+ }
+
+ /**
+ * Obtains a reference to the factory used to create, destroy and validate
+ * the objects used by this pool.
+ *
+ * @return the factory
+ */
+ public PooledObjectFactory<T> getFactory() {
+ return factory;
+ }
+
+ /**
+ * Equivalent to <code>{@link #borrowObject(long)
+ * borrowObject}({@link #getMaxWaitMillis()})</code>.
+ * <p>
+ * {@inheritDoc}
+ * </p>
+ */
+ @Override
+ public T borrowObject() throws Exception {
+ return borrowObject(getMaxWaitMillis());
+ }
+
+ /**
+ * Borrows an object from the pool using the specific waiting time which only
+ * applies if {@link #getBlockWhenExhausted()} is true.
+ * <p>
+ * If there is one or more idle instance available in the pool, then an
+ * idle instance will be selected based on the value of {@link #getLifo()},
+ * activated and returned. If activation fails, or {@link #getTestOnBorrow()
+ * testOnBorrow} is set to <code>true</code> and validation fails, the
+ * instance is destroyed and the next available instance is examined. This
+ * continues until either a valid instance is returned or there are no more
+ * idle instances available.
+ * </p>
+ * <p>
+ * If there are no idle instances available in the pool, behavior depends on
+ * the {@link #getMaxTotal() maxTotal}, (if applicable)
+ * {@link #getBlockWhenExhausted()} and the value passed in to the
+ * <code>borrowMaxWaitMillis</code> parameter. If the number of instances
+ * checked out from the pool is less than <code>maxTotal,</code> a new
+ * instance is created, activated and (if applicable) validated and returned
+ * to the caller. If validation fails, a <code>NoSuchElementException</code>
+ * is thrown.
+ * </p>
+ * <p>
+ * If the pool is exhausted (no available idle instances and no capacity to
+ * create new ones), this method will either block (if
+ * {@link #getBlockWhenExhausted()} is true) or throw a
+ * <code>NoSuchElementException</code> (if
+ * {@link #getBlockWhenExhausted()} is false). The length of time that this
+ * method will block when {@link #getBlockWhenExhausted()} is true is
+ * determined by the value passed in to the <code>borrowMaxWaitMillis</code>
+ * parameter.
+ * </p>
+ * <p>
+ * When the pool is exhausted, multiple calling threads may be
+ * simultaneously blocked waiting for instances to become available. A
+ * "fairness" algorithm has been implemented to ensure that threads receive
+ * available instances in request arrival order.
+ * </p>
+ *
+ * @param borrowMaxWaitMillis The time to wait in milliseconds for an object
+ * to become available
+ *
+ * @return object instance from the pool
+ *
+ * @throws NoSuchElementException if an instance cannot be returned
+ *
+ * @throws Exception if an object instance cannot be returned due to an
+ * error
+ */
+ public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
+ assertOpen();
+
+ final AbandonedConfig ac = this.abandonedConfig;
+ if (ac != null && ac.getRemoveAbandonedOnBorrow() &&
+ (getNumIdle() < 2) &&
+ (getNumActive() > getMaxTotal() - 3) ) {
+ removeAbandoned(ac);
+ }
+
+ PooledObject<T> p = null;
+
+ // Get local copy of current config so it is consistent for entire
+ // method execution
+ final boolean blockWhenExhausted = getBlockWhenExhausted();
+
+ boolean create;
+ final long waitTime = System.currentTimeMillis();
+
+ while (p == null) {
+ create = false;
+ p = idleObjects.pollFirst();
+ if (p == null) {
+ p = create();
+ if (p != null) {
+ create = true;
+ }
+ }
+ if (blockWhenExhausted) {
+ if (p == null) {
+ if (borrowMaxWaitMillis < 0) {
+ p = idleObjects.takeFirst();
+ } else {
+ p = idleObjects.pollFirst(borrowMaxWaitMillis,
+ TimeUnit.MILLISECONDS);
+ }
+ }
+ if (p == null) {
+ throw new NoSuchElementException(
+ "Timeout waiting for idle object");
+ }
+ } else {
+ if (p == null) {
+ throw new NoSuchElementException("Pool exhausted");
+ }
+ }
+ if (!p.allocate()) {
+ p = null;
+ }
+
+ if (p != null) {
+ try {
+ factory.activateObject(p);
+ } catch (final Exception e) {
+ try {
+ destroy(p);
+ } catch (final Exception e1) {
+ // Ignore - activation failure is more important
+ }
+ p = null;
+ if (create) {
+ final NoSuchElementException nsee = new NoSuchElementException(
+ "Unable to activate object");
+ nsee.initCause(e);
+ throw nsee;
+ }
+ }
+ if (p != null && (getTestOnBorrow() || create && getTestOnCreate())) {
+ boolean validate = false;
+ Throwable validationThrowable = null;
+ try {
+ validate = factory.validateObject(p);
+ } catch (final Throwable t) {
+ PoolUtils.checkRethrow(t);
+ validationThrowable = t;
+ }
+ if (!validate) {
+ try {
+ destroy(p);
+ destroyedByBorrowValidationCount.incrementAndGet();
+ } catch (final Exception e) {
+ // Ignore - validation failure is more important
+ }
+ p = null;
+ if (create) {
+ final NoSuchElementException nsee = new NoSuchElementException(
+ "Unable to validate object");
+ nsee.initCause(validationThrowable);
+ throw nsee;
+ }
+ }
+ }
+ }
+ }
+
+ updateStatsBorrow(p, System.currentTimeMillis() - waitTime);
+
+ return p.getObject();
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * If {@link #getMaxIdle() maxIdle} is set to a positive value and the
+ * number of idle instances has reached this value, the returning instance
+ * is destroyed.
+ * </p>
+ * <p>
+ * If {@link #getTestOnReturn() testOnReturn} == true, the returning
+ * instance is validated before being returned to the idle instance pool. In
+ * this case, if validation fails, the instance is destroyed.
+ * </p>
+ * <p>
+ * Exceptions encountered destroying objects for any reason are swallowed
+ * but notified via a {@link SwallowedExceptionListener}.
+ * </p>
+ */
+ @Override
+ public void returnObject(final T obj) {
+ final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
+
+ if (p == null) {
+ if (!isAbandonedConfig()) {
+ throw new IllegalStateException(
+ "Returned object not currently part of this pool");
+ }
+ return; // Object was abandoned and removed
+ }
+
+ markReturningState(p);
+
+ final long activeTime = p.getActiveTimeMillis();
+
+ if (getTestOnReturn() && !factory.validateObject(p)) {
+ try {
+ destroy(p);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ try {
+ ensureIdle(1, false);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ updateStatsReturn(activeTime);
+ return;
+ }
+
+ try {
+ factory.passivateObject(p);
+ } catch (final Exception e1) {
+ swallowException(e1);
+ try {
+ destroy(p);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ try {
+ ensureIdle(1, false);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ updateStatsReturn(activeTime);
+ return;
+ }
+
+ if (!p.deallocate()) {
+ throw new IllegalStateException(
+ "Object has already been returned to this pool or is invalid");
+ }
+
+ final int maxIdleSave = getMaxIdle();
+ if (isClosed() || maxIdleSave > -1 && maxIdleSave <= idleObjects.size()) {
+ try {
+ destroy(p);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ } else {
+ if (getLifo()) {
+ idleObjects.addFirst(p);
+ } else {
+ idleObjects.addLast(p);
+ }
+ if (isClosed()) {
+ // Pool closed while object was being added to idle objects.
+ // Make sure the returned object is destroyed rather than left
+ // in the idle object pool (which would effectively be a leak)
+ clear();
+ }
+ }
+ updateStatsReturn(activeTime);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Activation of this method decrements the active count and attempts to
+ * destroy the instance.
+ * </p>
+ *
+ * @throws Exception if an exception occurs destroying the
+ * object
+ * @throws IllegalStateException if obj does not belong to this pool
+ */
+ @Override
+ public void invalidateObject(final T obj) throws Exception {
+ final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
+ if (p == null) {
+ if (isAbandonedConfig()) {
+ return;
+ }
+ throw new IllegalStateException(
+ "Invalidated object not currently part of this pool");
+ }
+ synchronized (p) {
+ if (p.getState() != PooledObjectState.INVALID) {
+ destroy(p);
+ }
+ }
+ ensureIdle(1, false);
+ }
+
+ /**
+ * Clears any objects sitting idle in the pool by removing them from the
+ * idle instance pool and then invoking the configured
+ * {@link PooledObjectFactory#destroyObject(PooledObject)} method on each
+ * idle instance.
+ * <p>
+ * Implementation notes:
+ * </p>
+ * <ul>
+ * <li>This method does not destroy or effect in any way instances that are
+ * checked out of the pool when it is invoked.</li>
+ * <li>Invoking this method does not prevent objects being returned to the
+ * idle instance pool, even during its execution. Additional instances may
+ * be returned while removed items are being destroyed.</li>
+ * <li>Exceptions encountered destroying idle instances are swallowed
+ * but notified via a {@link SwallowedExceptionListener}.</li>
+ * </ul>
+ */
+ @Override
+ public void clear() {
+ PooledObject<T> p = idleObjects.poll();
+
+ while (p != null) {
+ try {
+ destroy(p);
+ } catch (final Exception e) {
+ swallowException(e);
+ }
+ p = idleObjects.poll();
+ }
+ }
+
+ @Override
+ public int getNumActive() {
+ return allObjects.size() - idleObjects.size();
+ }
+
+ @Override
+ public int getNumIdle() {
+ return idleObjects.size();
+ }
+
+ /**
+ * Closes the pool. Once the pool is closed, {@link #borrowObject()} will
+ * fail with IllegalStateException, but {@link #returnObject(Object)} and
+ * {@link #invalidateObject(Object)} will continue to work, with returned
+ * objects destroyed on return.
+ * <p>
+ * Destroys idle instances in the pool by invoking {@link #clear()}.
+ * </p>
+ */
+ @Override
+ public void close() {
+ if (isClosed()) {
+ return;
+ }
+
+ synchronized (closeLock) {
+ if (isClosed()) {
+ return;
+ }
+
+ // Stop the evictor before the pool is closed since evict() calls
+ // assertOpen()
+ stopEvitor();
+
+ closed = true;
+ // This clear removes any idle objects
+ clear();
+
+ jmxUnregister();
+
+ // Release any threads that were waiting for an object
+ idleObjects.interuptTakeWaiters();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Successive activations of this method examine objects in sequence,
+ * cycling through objects in oldest-to-youngest order.
+ * </p>
+ */
+ @Override
+ public void evict() throws Exception {
+ assertOpen();
+
+ if (idleObjects.size() > 0) {
+
+ PooledObject<T> underTest = null;
+ final EvictionPolicy<T> evictionPolicy = getEvictionPolicy();
+
+ synchronized (evictionLock) {
+ final EvictionConfig evictionConfig = new EvictionConfig(
+ getMinEvictableIdleTimeMillis(),
+ getSoftMinEvictableIdleTimeMillis(),
+ getMinIdle());
+
+ final boolean testWhileIdle = getTestWhileIdle();
+
+ for (int i = 0, m = getNumTests(); i < m; i++) {
+ if (evictionIterator == null || !evictionIterator.hasNext()) {
+ evictionIterator = new EvictionIterator(idleObjects);
+ }
+ if (!evictionIterator.hasNext()) {
+ // Pool exhausted, nothing to do here
+ return;
+ }
+
+ try {
+ underTest = evictionIterator.next();
+ } catch (final NoSuchElementException nsee) {
+ // Object was borrowed in another thread
+ // Don't count this as an eviction test so reduce i;
+ i--;
+ evictionIterator = null;
+ continue;
+ }
+
+ if (!underTest.startEvictionTest()) {
+ // Object was borrowed in another thread
+ // Don't count this as an eviction test so reduce i;
+ i--;
+ continue;
+ }
+
+ // User provided eviction policy could throw all sorts of
+ // crazy exceptions. Protect against such an exception
+ // killing the eviction thread.
+ boolean evict;
+ try {
+ evict = evictionPolicy.evict(evictionConfig, underTest,
+ idleObjects.size());
+ } catch (final Throwable t) {
+ // Slightly convoluted as SwallowedExceptionListener
+ // uses Exception rather than Throwable
+ PoolUtils.checkRethrow(t);
+ swallowException(new Exception(t));
+ // Don't evict on error conditions
+ evict = false;
+ }
+
+ if (evict) {
+ destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
+ } else {
+ if (testWhileIdle) {
+ boolean active = false;
+ try {
+ factory.activateObject(underTest);
+ active = true;
+ } catch (final Exception e) {
+ destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
+ }
+ if (active) {
+ if (!factory.validateObject(underTest)) {
+ destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
+ } else {
+ try {
+ factory.passivateObject(underTest);
+ } catch (final Exception e) {
+ destroy(underTest);
+ destroyedByEvictorCount.incrementAndGet();
+ }
+ }
+ }
+ }
+ if (!underTest.endEvictionTest(idleObjects)) {
+ // TODO - May need to add code here once additional
+ // states are used
+ }
+ }
+ }
+ }
+ }
+ final AbandonedConfig ac = this.abandonedConfig;
+ if (ac != null && ac.getRemoveAbandonedOnMaintenance()) {
+ removeAbandoned(ac);
+ }
+ }
+
+ /**
+ * Tries to ensure that {@link #getMinIdle()} idle instances are available
+ * in the pool.
+ *
+ * @throws Exception If the associated factory throws an exception
+ * @since 2.4
+ */
+ public void preparePool() throws Exception {
+ if (getMinIdle() < 1) {
+ return;
+ }
+ ensureMinIdle();
+ }
+
+ /**
+ * Attempts to create a new wrapped pooled object.
+ * <p>
+ * If there are {@link #getMaxTotal()} objects already in circulation
+ * or in process of being created, this method returns null.
+ * </p>
+ *
+ * @return The new wrapped pooled object
+ *
+ * @throws Exception if the object factory's {@code makeObject} fails
+ */
+ private PooledObject<T> create() throws Exception {
+ int localMaxTotal = getMaxTotal();
+ // This simplifies the code later in this method
+ if (localMaxTotal < 0) {
+ localMaxTotal = Integer.MAX_VALUE;
+ }
+
+ final long localStartTimeMillis = System.currentTimeMillis();
+ final long localMaxWaitTimeMillis = Math.max(getMaxWaitMillis(), 0);
+
+ // Flag that indicates if create should:
+ // - TRUE: call the factory to create an object
+ // - FALSE: return null
+ // - null: loop and re-test the condition that determines whether to
+ // call the factory
+ Boolean create = null;
+ while (create == null) {
+ synchronized (makeObjectCountLock) {
+ final long newCreateCount = createCount.incrementAndGet();
+ if (newCreateCount > localMaxTotal) {
+ // The pool is currently at capacity or in the process of
+ // making enough new objects to take it to capacity.
+ createCount.decrementAndGet();
+ if (makeObjectCount == 0) {
+ // There are no makeObject() calls in progress so the
+ // pool is at capacity. Do not attempt to create a new
+ // object. Return and wait for an object to be returned
+ create = Boolean.FALSE;
+ } else {
+ // There are makeObject() calls in progress that might
+ // bring the pool to capacity. Those calls might also
+ // fail so wait until they complete and then re-test if
+ // the pool is at capacity or not.
+ makeObjectCountLock.wait(localMaxWaitTimeMillis);
+ }
+ } else {
+ // The pool is not at capacity. Create a new object.
+ makeObjectCount++;
+ create = Boolean.TRUE;
+ }
+ }
+
+ // Do not block more if maxWaitTimeMillis is set.
+ if (create == null &&
+ (localMaxWaitTimeMillis > 0 &&
+ System.currentTimeMillis() - localStartTimeMillis >= localMaxWaitTimeMillis)) {
+ create = Boolean.FALSE;
+ }
+ }
+
+ if (!create.booleanValue()) {
+ return null;
+ }
+
+ final PooledObject<T> p;
+ try {
+ p = factory.makeObject();
+ } catch (final Throwable e) {
+ createCount.decrementAndGet();
+ throw e;
+ } finally {
+ synchronized (makeObjectCountLock) {
+ makeObjectCount--;
+ makeObjectCountLock.notifyAll();
+ }
+ }
+
+ final AbandonedConfig ac = this.abandonedConfig;
+ if (ac != null && ac.getLogAbandoned()) {
+ p.setLogAbandoned(true);
+ // TODO: in 3.0, this can use the method defined on PooledObject
+ if (p instanceof DefaultPooledObject<?>) {
+ ((DefaultPooledObject<T>) p).setRequireFullStackTrace(ac.getRequireFullStackTrace());
+ }
+ }
+
+ createdCount.incrementAndGet();
+ allObjects.put(new IdentityWrapper<>(p.getObject()), p);
+ return p;
+ }
+
+ /**
+ * Destroys a wrapped pooled object.
+ *
+ * @param toDestroy The wrapped pooled object to destroy
+ *
+ * @throws Exception If the factory fails to destroy the pooled object
+ * cleanly
+ */
+ private void destroy(final PooledObject<T> toDestroy) throws Exception {
+ toDestroy.invalidate();
+ idleObjects.remove(toDestroy);
+ allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
+ try {
+ factory.destroyObject(toDestroy);
+ } finally {
+ destroyedCount.incrementAndGet();
+ createCount.decrementAndGet();
+ }
+
+ if (idleObjects.isEmpty() && idleObjects.hasTakeWaiters()) {
+ // POOL-356.
+ // In case there are already threads waiting on something in the pool
+ // (e.g. idleObjects.takeFirst(); then we need to provide them a fresh instance.
+ // Otherwise they will be stuck forever (or until timeout)
+ final PooledObject<T> freshPooled = create();
+ idleObjects.put(freshPooled);
+ }
+ }
+
+ @Override
+ void ensureMinIdle() throws Exception {
+ ensureIdle(getMinIdle(), true);
+ }
+
+ /**
+ * Tries to ensure that {@code idleCount} idle instances exist in the pool.
+ * <p>
+ * Creates and adds idle instances until either {@link #getNumIdle()} reaches {@code idleCount}
+ * or the total number of objects (idle, checked out, or being created) reaches
+ * {@link #getMaxTotal()}. If {@code always} is false, no instances are created unless
+ * there are threads waiting to check out instances from the pool.
+ * </p>
+ *
+ * @param idleCount the number of idle instances desired
+ * @param always true means create instances even if the pool has no threads waiting
+ * @throws Exception if the factory's makeObject throws
+ */
+ private void ensureIdle(final int idleCount, final boolean always) throws Exception {
+ if (idleCount < 1 || isClosed() || (!always && !idleObjects.hasTakeWaiters())) {
+ return;
+ }
+
+ while (idleObjects.size() < idleCount) {
+ final PooledObject<T> p = create();
+ if (p == null) {
+ // Can't create objects, no reason to think another call to
+ // create will work. Give up.
+ break;
+ }
+ if (getLifo()) {
+ idleObjects.addFirst(p);
+ } else {
+ idleObjects.addLast(p);
+ }
+ }
+ if (isClosed()) {
+ // Pool closed while object was being added to idle objects.
+ // Make sure the returned object is destroyed rather than left
+ // in the idle object pool (which would effectively be a leak)
+ clear();
+ }
+ }
+
+ /**
+ * Creates an object, and place it into the pool. addObject() is useful for
+ * "pre-loading" a pool with idle objects.
+ * <p>
+ * If there is no capacity available to add to the pool, this is a no-op
+ * (no exception, no impact to the pool). </p>
+ */
+ @Override
+ public void addObject() throws Exception {
+ assertOpen();
+ if (factory == null) {
+ throw new IllegalStateException(
+ "Cannot add objects without a factory.");
+ }
+ final PooledObject<T> p = create();
+ addIdleObject(p);
+ }
+
+ /**
+ * Adds the provided wrapped pooled object to the set of idle objects for
+ * this pool. The object must already be part of the pool. If {@code p}
+ * is null, this is a no-op (no exception, but no impact on the pool).
+ *
+ * @param p The object to make idle
+ *
+ * @throws Exception If the factory fails to passivate the object
+ */
+ private void addIdleObject(final PooledObject<T> p) throws Exception {
+ if (p != null) {
+ factory.passivateObject(p);
+ if (getLifo()) {
+ idleObjects.addFirst(p);
+ } else {
+ idleObjects.addLast(p);
+ }
+ }
+ }
+
+ /**
+ * Calculates the number of objects to test in a run of the idle object
+ * evictor.
+ *
+ * @return The number of objects to test for validity
+ */
+ private int getNumTests() {
+ final int numTestsPerEvictionRun = getNumTestsPerEvictionRun();
+ if (numTestsPerEvictionRun >= 0) {
+ return Math.min(numTestsPerEvictionRun, idleObjects.size());
+ }
+ return (int) (Math.ceil(idleObjects.size() /
+ Math.abs((double) numTestsPerEvictionRun)));
+ }
+
+ /**
+ * Recovers abandoned objects which have been checked out but
+ * not used since longer than the removeAbandonedTimeout.
+ *
+ * @param ac The configuration to use to identify abandoned objects
+ */
+ private void removeAbandoned(final AbandonedConfig ac) {
+ // Generate a list of abandoned objects to remove
+ final long now = System.currentTimeMillis();
+ final long timeout =
+ now - (ac.getRemoveAbandonedTimeout() * 1000L);
+ final ArrayList<PooledObject<T>> remove = new ArrayList<>();
+ final Iterator<PooledObject<T>> it = allObjects.values().iterator();
+ while (it.hasNext()) {
+ final PooledObject<T> pooledObject = it.next();
+ synchronized (pooledObject) {
+ if (pooledObject.getState() == PooledObjectState.ALLOCATED &&
+ pooledObject.getLastUsedTime() <= timeout) {
+ pooledObject.markAbandoned();
+ remove.add(pooledObject);
+ }
+ }
+ }
+
+ // Now remove the abandoned objects
+ final Iterator<PooledObject<T>> itr = remove.iterator();
+ while (itr.hasNext()) {
+ final PooledObject<T> pooledObject = itr.next();
+ if (ac.getLogAbandoned()) {
+ pooledObject.printStackTrace(ac.getLogWriter());
+ }
+ try {
+ invalidateObject(pooledObject.getObject());
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ //--- Usage tracking support -----------------------------------------------
+
+ @Override
+ public void use(final T pooledObject) {
+ final AbandonedConfig ac = this.abandonedConfig;
+ if (ac != null && ac.getUseUsageTracking()) {
+ final PooledObject<T> wrapper = allObjects.get(new IdentityWrapper<>(pooledObject));
+ wrapper.use();
+ }
+ }
+
+
+ //--- JMX support ----------------------------------------------------------
+
+ private volatile String factoryType = null;
+
+ /**
+ * Returns an estimate of the number of threads currently blocked waiting for
+ * an object from the pool. This is intended for monitoring only, not for
+ * synchronization control.
+ *
+ * @return The estimate of the number of threads currently blocked waiting
+ * for an object from the pool
+ */
+ @Override
+ public int getNumWaiters() {
+ if (getBlockWhenExhausted()) {
+ return idleObjects.getTakeQueueLength();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the type - including the specific type rather than the generic -
+ * of the factory.
+ *
+ * @return A string representation of the factory type
+ */
+ @Override
+ public String getFactoryType() {
+ // Not thread safe. Accept that there may be multiple evaluations.
+ if (factoryType == null) {
+ final StringBuilder result = new StringBuilder();
+ result.append(factory.getClass().getName());
+ result.append('<');
+ final Class<?> pooledObjectType =
+ PoolImplUtils.getFactoryType(factory.getClass());
+ result.append(pooledObjectType.getName());
+ result.append('>');
+ factoryType = result.toString();
+ }
+ return factoryType;
+ }
+
+ /**
+ * Provides information on all the objects in the pool, both idle (waiting
+ * to be borrowed) and active (currently borrowed).
+ * <p>
+ * Note: This is named listAllObjects so it is presented as an operation via
+ * JMX. That means it won't be invoked unless the explicitly requested
+ * whereas all attributes will be automatically requested when viewing the
+ * attributes for an object in a tool like JConsole.
+ * </p>
+ *
+ * @return Information grouped on all the objects in the pool
+ */
+ @Override
+ public Set<DefaultPooledObjectInfo> listAllObjects() {
+ final Set<DefaultPooledObjectInfo> result =
+ new HashSet<>(allObjects.size());
+ for (final PooledObject<T> p : allObjects.values()) {
+ result.add(new DefaultPooledObjectInfo(p));
+ }
+ return result;
+ }
+
+ // --- configuration attributes --------------------------------------------
+
+ private volatile int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
+ private volatile int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
+ private final PooledObjectFactory<T> factory;
+
+
+ // --- internal attributes -------------------------------------------------
+
+ /*
+ * All of the objects currently associated with this pool in any state. It
+ * excludes objects that have been destroyed. The size of
+ * {@link #allObjects} will always be less than or equal to {@link
+ * #_maxActive}. Map keys are pooled objects, values are the PooledObject
+ * wrappers used internally by the pool.
+ */
+ private final Map<IdentityWrapper<T>, PooledObject<T>> allObjects =
+ new ConcurrentHashMap<>();
+ /*
+ * The combined count of the currently created objects and those in the
+ * process of being created. Under load, it may exceed {@link #_maxActive}
+ * if multiple threads try and create a new object at the same time but
+ * {@link #create()} will ensure that there are never more than
+ * {@link #_maxActive} objects created at any one time.
+ */
+ private final AtomicLong createCount = new AtomicLong(0);
+ private long makeObjectCount = 0;
+ private final Object makeObjectCountLock = new Object();
+ private final LinkedBlockingDeque<PooledObject<T>> idleObjects;
+
+ // JMX specific attributes
+ private static final String ONAME_BASE =
+ "org.apache.commons.pool2:type=GenericObjectPool,name=";
+
+ // Additional configuration properties for abandoned object tracking
+ private volatile AbandonedConfig abandonedConfig = null;
+
+ @Override
+ protected void toStringAppendFields(final StringBuilder builder) {
+ super.toStringAppendFields(builder);
+ builder.append(", factoryType=");
+ builder.append(factoryType);
+ builder.append(", maxIdle=");
+ builder.append(maxIdle);
+ builder.append(", minIdle=");
+ builder.append(minIdle);
+ builder.append(", factory=");
+ builder.append(factory);
+ builder.append(", allObjects=");
+ builder.append(allObjects);
+ builder.append(", createCount=");
+ builder.append(createCount);
+ builder.append(", idleObjects=");
+ builder.append(idleObjects);
+ builder.append(", abandonedConfig=");
+ builder.append(abandonedConfig);
+ }
+
+}