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 06ba7ce Add DestroyMode to provide context to destroyObject
activations. Fixes POOL-387, needed by DBCP-567. (#43)
06ba7ce is described below
commit 06ba7ceb61f4a238307010bacc98c10241a1a243
Author: Phil Steitz <[email protected]>
AuthorDate: Mon Sep 14 07:07:14 2020 -0700
Add DestroyMode to provide context to destroyObject activations. Fixes
POOL-387, needed by DBCP-567. (#43)
---
.../java/org/apache/commons/pool2/DestroyMode.java | 31 +++++++++++++
.../org/apache/commons/pool2/KeyedObjectPool.java | 27 +++++++++++
.../commons/pool2/KeyedPooledObjectFactory.java | 19 ++++++++
.../java/org/apache/commons/pool2/ObjectPool.java | 24 ++++++++++
.../apache/commons/pool2/PooledObjectFactory.java | 22 ++++++++-
.../commons/pool2/impl/GenericKeyedObjectPool.java | 53 ++++++++++++++++------
.../commons/pool2/impl/GenericObjectPool.java | 48 ++++++++++++++------
.../pool2/TestBasePoolableObjectFactory.java | 37 +++++++++++++--
.../pool2/impl/TestAbandonedObjectPool.java | 45 +++++++++++++++++-
9 files changed, 268 insertions(+), 38 deletions(-)
diff --git a/src/main/java/org/apache/commons/pool2/DestroyMode.java
b/src/main/java/org/apache/commons/pool2/DestroyMode.java
new file mode 100644
index 0000000..09b1594
--- /dev/null
+++ b/src/main/java/org/apache/commons/pool2/DestroyMode.java
@@ -0,0 +1,31 @@
+/*
+ * 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;
+
+/**
+ * Destroy context provided to object factories via destroyObject methods.
+ * Values provide information about why the pool is asking for a pooled object
+ * to be destroyed.
+ *
+ * @since 2.8.2
+ */
+public enum DestroyMode {
+ /** Normal destroy */
+ NORMAL,
+ /** Destroy abandoned object */
+ ABANDONED
+}
diff --git a/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
b/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
index 9cca6e2..e47588a 100644
--- a/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/KeyedObjectPool.java
@@ -270,6 +270,33 @@ public interface KeyedObjectPool<K, V> extends Closeable {
* @throws Exception if the instance cannot be invalidated
*/
void invalidateObject(K key, V obj) throws Exception;
+
+
+ /**
+ * Invalidates an object from the pool, using the provided
+ * {@link DestroyMode}.
+ * <p>
+ * By contract, {@code obj} <strong>must</strong> have been obtained
+ * using {@link #borrowObject borrowObject} or a related method as defined
+ * in an implementation or sub-interface using a {@code key} that is
+ * equivalent to the one used to borrow the {@code Object} in the first
+ * place.
+ * </p>
+ * <p>
+ * This method should be used when an object that has been borrowed is
+ * determined (due to an exception or other problem) to be invalid.
+ * </p>
+ *
+ * @param key the key used to obtain the object
+ * @param obj a {@link #borrowObject borrowed} instance to be returned.
+ * @param mode destroy activation context provided to the factory
+ *
+ * @throws Exception if the instance cannot be invalidated
+ */
+ default void invalidateObject(K key, V obj, DestroyMode mode)
+ throws Exception {
+ invalidateObject(key, obj);
+ }
/**
* Return an instance to the pool. By contract, {@code obj}
diff --git
a/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
b/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
index bb753cf..37f14ad 100644
--- a/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
+++ b/src/main/java/org/apache/commons/pool2/KeyedPooledObjectFactory.java
@@ -112,6 +112,25 @@ public interface KeyedPooledObjectFactory<K, V> {
* @see KeyedObjectPool#invalidateObject
*/
void destroyObject(K key, PooledObject<V> p) throws Exception;
+
+ /**
+ * Destroy an instance no longer needed by the pool, using the provided
{@link DestroyMode}.
+ *
+ * @param key the key used when selecting the instance
+ * @param p a {@code PooledObject} wrapping the instance to be destroyed
+ * @param mode DestroyMode providing context to the factory
+ *
+ * @throws Exception should be avoided as it may be swallowed by
+ * the pool implementation.
+ *
+ * @see #validateObject
+ * @see KeyedObjectPool#invalidateObject
+ * @see #destroyObject(Object, PooledObject)
+ * @see DestroyMode
+ */
+ default void destroyObject(K key, PooledObject<V> p, DestroyMode mode)
throws Exception {
+ destroyObject(key, p);
+ }
/**
* Ensures that the instance is safe to be returned by the pool.
diff --git a/src/main/java/org/apache/commons/pool2/ObjectPool.java
b/src/main/java/org/apache/commons/pool2/ObjectPool.java
index ca998fc..dcc384d 100644
--- a/src/main/java/org/apache/commons/pool2/ObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/ObjectPool.java
@@ -183,6 +183,29 @@ public interface ObjectPool<T> extends Closeable {
* @throws Exception if the instance cannot be invalidated
*/
void invalidateObject(T obj) throws Exception;
+
+ /**
+ * Invalidates an object from the pool, using the provided
+ * {@link DestroyMode}
+ * <p>
+ * By contract, {@code obj} <strong>must</strong> have been obtained
+ * using {@link #borrowObject} or a related method as defined in an
+ * implementation or sub-interface.
+ * </p>
+ * <p>
+ * This method should be used when an object that has been borrowed is
+ * determined (due to an exception or other problem) to be invalid.
+ * </p>
+ *
+ * @param obj a {@link #borrowObject borrowed} instance to be disposed.
+ * @param mode destroy activation context provided to the factory
+ *
+ * @throws Exception if the instance cannot be invalidated
+ */
+ default void invalidateObject(T obj, DestroyMode mode)
+ throws Exception {
+ invalidateObject(obj);
+ }
/**
* Returns an instance to the pool. By contract, {@code obj}
@@ -201,4 +224,5 @@ public interface ObjectPool<T> extends Closeable {
* @throws Exception if an instance cannot be returned to the pool
*/
void returnObject(T obj) throws Exception;
+
}
diff --git a/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
b/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
index cc7f794..d16e3c1 100644
--- a/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
+++ b/src/main/java/org/apache/commons/pool2/PooledObjectFactory.java
@@ -84,7 +84,8 @@ public interface PooledObjectFactory<T> {
PooledObject<T> makeObject() throws Exception;
/**
- * Destroys an instance no longer needed by the pool.
+ * Destroys an instance no longer needed by the pool, using the default
(NORMAL)
+ * DestroyMode.
* <p>
* It is important for implementations of this method to be aware that there
* is no guarantee about what state {@code obj} will be in and the
@@ -104,6 +105,25 @@ public interface PooledObjectFactory<T> {
* @see ObjectPool#invalidateObject
*/
void destroyObject(PooledObject<T> p) throws Exception;
+
+ /**
+ * Destroys an instance no longer needed by the pool, using the provided
+ * DestroyMode.
+ *
+ * @param p a {@code PooledObject} wrapping the instance to be destroyed
+ * @param mode DestroyMode providing context to the factory
+ *
+ * @throws Exception should be avoided as it may be swallowed by
+ * the pool implementation.
+ *
+ * @see #validateObject
+ * @see ObjectPool#invalidateObject
+ * @see #destroyObject(PooledObject)
+ * @see DestroyMode
+ */
+ default void destroyObject(PooledObject<T> p, DestroyMode mode) throws
Exception {
+ destroyObject(p);
+ }
/**
* Ensures that the instance is safe to be returned by the pool.
diff --git
a/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
b/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
index 310c4e7..ef661eb 100644
--- a/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/impl/GenericKeyedObjectPool.java
@@ -33,6 +33,7 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import org.apache.commons.pool2.DestroyMode;
import org.apache.commons.pool2.KeyedObjectPool;
import org.apache.commons.pool2.KeyedPooledObjectFactory;
import org.apache.commons.pool2.PoolUtils;
@@ -376,7 +377,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
factory.activateObject(key, p);
} catch (final Exception e) {
try {
- destroy(key, p, true);
+ destroy(key, p, true, DestroyMode.NORMAL);
} catch (final Exception e1) {
// Ignore - activation failure is more important
}
@@ -399,7 +400,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
}
if (!validate) {
try {
- destroy(key, p, true);
+ destroy(key, p, true, DestroyMode.NORMAL);
destroyedByBorrowValidationCount.incrementAndGet();
} catch (final Exception e) {
// Ignore - validation failure is more
important
@@ -471,7 +472,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
try {
if (getTestOnReturn() && !factory.validateObject(key, p)) {
try {
- destroy(key, p, true);
+ destroy(key, p, true, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -484,7 +485,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
} catch (final Exception e1) {
swallowException(e1);
try {
- destroy(key, p, true);
+ destroy(key, p, true, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -503,7 +504,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
if (isClosed() || maxIdle > -1 && maxIdle <= idleObjects.size()) {
try {
- destroy(key, p, true);
+ destroy(key, p, true, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -542,7 +543,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
}
}
}
-
+
/**
* {@inheritDoc}
* <p>
@@ -559,6 +560,26 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
*/
@Override
public void invalidateObject(final K key, final T obj) throws Exception {
+ invalidateObject(key, obj, DestroyMode.NORMAL);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Activation of this method decrements the active count associated with
+ * the given keyed pool and attempts to destroy {@code obj.}
+ *
+ * @param key pool key
+ * @param obj instance to invalidate
+ * @param mode DestroyMode context provided to factory
+ *
+ * @throws Exception if an exception occurs destroying the
+ * object
+ * @throws IllegalStateException if obj does not belong to the pool
+ * under the given key
+ */
+ @Override
+ public void invalidateObject(final K key, final T obj, DestroyMode mode)
throws Exception {
final ObjectDeque<T> objectDeque = poolMap.get(key);
@@ -569,7 +590,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
}
synchronized (p) {
if (p.getState() != PooledObjectState.INVALID) {
- destroy(key, p, true);
+ destroy(key, p, true, mode);
}
}
if (objectDeque.idleObjects.hasTakeWaiters()) {
@@ -627,7 +648,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
while (p != null) {
try {
- destroy(key, p, true);
+ destroy(key, p, true, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -760,7 +781,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
// Assume the destruction succeeds
boolean destroyed = true;
try {
- destroyed = destroy(key, p, false);
+ destroyed = destroy(key, p, false, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -937,7 +958,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
}
if (evict) {
- destroy(evictionKey, underTest, true);
+ destroy(evictionKey, underTest, true, DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
} else {
if (testWhileIdle) {
@@ -946,18 +967,18 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
factory.activateObject(evictionKey, underTest);
active = true;
} catch (final Exception e) {
- destroy(evictionKey, underTest, true);
+ destroy(evictionKey, underTest, true,
DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
}
if (active) {
if (!factory.validateObject(evictionKey,
underTest)) {
- destroy(evictionKey, underTest, true);
+ destroy(evictionKey, underTest, true,
DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
} else {
try {
factory.passivateObject(evictionKey,
underTest);
} catch (final Exception e) {
- destroy(evictionKey, underTest, true);
+ destroy(evictionKey, underTest, true,
DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
}
}
@@ -1077,10 +1098,12 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
* @param toDestroy The wrapped object to be destroyed
* @param always Should the object be destroyed even if it is not currently
* in the set of idle objects for the given key
+ * @param mode DestroyMode context provided to the factory
+ *
* @return {@code true} if the object was destroyed, otherwise {@code
false}
* @throws Exception If the object destruction failed
*/
- private boolean destroy(final K key, final PooledObject<T> toDestroy,
final boolean always)
+ private boolean destroy(final K key, final PooledObject<T> toDestroy,
final boolean always, DestroyMode mode)
throws Exception {
final ObjectDeque<T> objectDeque = register(key);
@@ -1101,7 +1124,7 @@ public class GenericKeyedObjectPool<K, T> extends
BaseGenericObjectPool<T>
toDestroy.invalidate();
try {
- factory.destroyObject(key, toDestroy);
+ factory.destroyObject(key, toDestroy, mode);
} finally {
objectDeque.getCreateCount().decrementAndGet();
destroyedCount.incrementAndGet();
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 09c7c5c..e791ad7 100644
--- a/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
+++ b/src/main/java/org/apache/commons/pool2/impl/GenericObjectPool.java
@@ -16,6 +16,7 @@
*/
package org.apache.commons.pool2.impl;
+import org.apache.commons.pool2.DestroyMode;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.PoolUtils;
import org.apache.commons.pool2.PooledObject;
@@ -458,7 +459,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
factory.activateObject(p);
} catch (final Exception e) {
try {
- destroy(p);
+ destroy(p, DestroyMode.NORMAL);
} catch (final Exception e1) {
// Ignore - activation failure is more important
}
@@ -481,7 +482,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
}
if (!validate) {
try {
- destroy(p);
+ destroy(p, DestroyMode.NORMAL);
destroyedByBorrowValidationCount.incrementAndGet();
} catch (final Exception e) {
// Ignore - validation failure is more important
@@ -538,7 +539,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
if (getTestOnReturn() && !factory.validateObject(p)) {
try {
- destroy(p);
+ destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -556,7 +557,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
} catch (final Exception e1) {
swallowException(e1);
try {
- destroy(p);
+ destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -577,7 +578,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
final int maxIdleSave = getMaxIdle();
if (isClosed() || maxIdleSave > -1 && maxIdleSave <=
idleObjects.size()) {
try {
- destroy(p);
+ destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -606,7 +607,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
* {@inheritDoc}
* <p>
* Activation of this method decrements the active count and attempts to
- * destroy the instance.
+ * destroy the instance, using the default (NORMAL) {@link DestroyMode}.
* </p>
*
* @throws Exception if an exception occurs destroying the
@@ -615,6 +616,22 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
*/
@Override
public void invalidateObject(final T obj) throws Exception {
+ invalidateObject(obj, DestroyMode.NORMAL);
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Activation of this method decrements the active count and attempts to
+ * destroy the instance, using the provided {@link DestroyMode}.
+ * </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, DestroyMode mode) throws
Exception {
final PooledObject<T> p = allObjects.get(new IdentityWrapper<>(obj));
if (p == null) {
if (isAbandonedConfig()) {
@@ -625,7 +642,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
}
synchronized (p) {
if (p.getState() != PooledObjectState.INVALID) {
- destroy(p);
+ destroy(p, mode);
}
}
ensureIdle(1, false);
@@ -655,7 +672,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
while (p != null) {
try {
- destroy(p);
+ destroy(p, DestroyMode.NORMAL);
} catch (final Exception e) {
swallowException(e);
}
@@ -775,7 +792,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
}
if (evict) {
- destroy(underTest);
+ destroy(underTest, DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
} else {
if (testWhileIdle) {
@@ -784,18 +801,18 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
factory.activateObject(underTest);
active = true;
} catch (final Exception e) {
- destroy(underTest);
+ destroy(underTest, DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
}
if (active) {
if (!factory.validateObject(underTest)) {
- destroy(underTest);
+ destroy(underTest, DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
} else {
try {
factory.passivateObject(underTest);
} catch (final Exception e) {
- destroy(underTest);
+ destroy(underTest, DestroyMode.NORMAL);
destroyedByEvictorCount.incrementAndGet();
}
}
@@ -926,16 +943,17 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
* Destroys a wrapped pooled object.
*
* @param toDestroy The wrapped pooled object to destroy
+ * @param mode DestroyMode context provided to the factory
*
* @throws Exception If the factory fails to destroy the pooled object
* cleanly
*/
- private void destroy(final PooledObject<T> toDestroy) throws Exception {
+ private void destroy(final PooledObject<T> toDestroy, final DestroyMode
mode) throws Exception {
toDestroy.invalidate();
idleObjects.remove(toDestroy);
allObjects.remove(new IdentityWrapper<>(toDestroy.getObject()));
try {
- factory.destroyObject(toDestroy);
+ factory.destroyObject(toDestroy, mode);
} finally {
destroyedCount.incrementAndGet();
createCount.decrementAndGet();
@@ -1071,7 +1089,7 @@ public class GenericObjectPool<T> extends
BaseGenericObjectPool<T>
pooledObject.printStackTrace(ac.getLogWriter());
}
try {
- invalidateObject(pooledObject.getObject());
+ invalidateObject(pooledObject.getObject(),
DestroyMode.ABANDONED);
} catch (final Exception e) {
e.printStackTrace();
}
diff --git
a/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
b/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
index 11fa724..b19d934 100644
--- a/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
+++ b/src/test/java/org/apache/commons/pool2/TestBasePoolableObjectFactory.java
@@ -16,8 +16,11 @@
*/
package org.apache.commons.pool2;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.util.concurrent.atomic.AtomicInteger;
+
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.junit.Test;
@@ -27,21 +30,45 @@ public class TestBasePoolableObjectFactory {
@Test
public void testDefaultMethods() throws Exception {
- final PooledObjectFactory<Object> factory = new TestFactory();
+ final PooledObjectFactory<AtomicInteger> factory = new TestFactory();
factory.activateObject(null); // a no-op
factory.passivateObject(null); // a no-op
factory.destroyObject(null); // a no-op
assertTrue(factory.validateObject(null)); // constant true
}
+
+ /**
+ * Default destroy does nothing to underlying AtomicInt, ABANDONED mode
+ * increments the value. Verify that destroy with no mode does default,
+ * destroy with ABANDONED mode increments.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testDestroyModes() throws Exception {
+ final PooledObjectFactory<AtomicInteger> factory = new TestFactory();
+ final PooledObject<AtomicInteger> pooledObj = factory.makeObject();
+ final AtomicInteger obj = pooledObj.getObject();
+ factory.destroyObject(pooledObj);
+ assertEquals(0, obj.get());
+ factory.destroyObject(pooledObj, DestroyMode.ABANDONED);
+ assertEquals(1, obj.get());
+ }
- private static class TestFactory extends BasePooledObjectFactory<Object> {
+ private static class TestFactory extends
BasePooledObjectFactory<AtomicInteger> {
@Override
- public Object create() throws Exception {
- return null;
+ public AtomicInteger create() throws Exception {
+ return new AtomicInteger(0);
}
+ @Override
+ public void destroyObject(PooledObject<AtomicInteger> p, DestroyMode
mode){
+ if (mode.equals(DestroyMode.ABANDONED)) {
+ p.getObject().incrementAndGet();
+ }
+ }
@Override
- public PooledObject<Object> wrap(final Object value) {
+ public PooledObject<AtomicInteger> wrap(final AtomicInteger value) {
return new DefaultPooledObject<>(value);
}
}
diff --git
a/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
b/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
index 0c9ebfd..6f0634b 100644
--- a/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
+++ b/src/test/java/org/apache/commons/pool2/impl/TestAbandonedObjectPool.java
@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import org.apache.commons.pool2.DestroyMode;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.TrackedUse;
@@ -199,6 +200,33 @@ public class TestAbandonedObjectPool {
Assert.assertEquals(0, pool.getNumActive());
Assert.assertEquals(5, pool.getDestroyedCount());
}
+
+ public void testDestroyModeAbandoned() throws Exception {
+ abandonedConfig = new AbandonedConfig();
+ abandonedConfig.setRemoveAbandonedOnMaintenance(true);
+ abandonedConfig.setRemoveAbandonedTimeout(1);
+ pool.close(); // Unregister pool created by setup
+ pool = new GenericObjectPool<>(
+ // validate takes 1 second
+ new SimpleFactory(0, 0),
+ new GenericObjectPoolConfig<PooledTestObject>(), abandonedConfig);
+ pool.setTimeBetweenEvictionRunsMillis(50);
+ // Borrow an object, wait long enough for it to be abandoned
+ final PooledTestObject obj = pool.borrowObject();
+ Thread.sleep(100);
+ Assert.assertTrue(obj.isDetached());
+ }
+
+ public void testDestroyModeNormal() throws Exception {
+ abandonedConfig = new AbandonedConfig();
+ pool.close(); // Unregister pool created by setup
+ pool = new GenericObjectPool<>(new SimpleFactory(0, 0));
+ pool.setMaxIdle(0);
+ final PooledTestObject obj = pool.borrowObject();
+ pool.returnObject(obj);
+ Assert.assertTrue(obj.isDestroyed());
+ Assert.assertFalse(obj.isDetached());
+ }
/**
* Verify that an object that the evictor identifies as abandoned while it
@@ -358,6 +386,11 @@ public class TestAbandonedObjectPool {
@Override
public void destroyObject(final PooledObject<PooledTestObject> obj)
throws Exception {
+ destroyObject(obj, DestroyMode.NORMAL);
+ }
+
+ @Override
+ public void destroyObject(final PooledObject<PooledTestObject> obj,
DestroyMode mode) throws Exception {
obj.getObject().setActive(false);
// while destroying instances, yield control to other threads
// helps simulate threading errors
@@ -365,7 +398,7 @@ public class TestAbandonedObjectPool {
if (destroyLatency != 0) {
Thread.sleep(destroyLatency);
}
- obj.getObject().destroy();
+ obj.getObject().destroy(mode);
}
}
}
@@ -376,6 +409,7 @@ class PooledTestObject implements TrackedUse {
private int _hash = 0;
private boolean _abandoned = false;
private static final AtomicInteger hash = new AtomicInteger();
+ private boolean detached = false; // destroy-abandoned "detaches"
public PooledTestObject() {
_hash = hash.incrementAndGet();
@@ -389,13 +423,20 @@ class PooledTestObject implements TrackedUse {
return active;
}
- public void destroy() {
+ public void destroy(DestroyMode mode) {
destroyed = true;
+ if (mode.equals(DestroyMode.ABANDONED)) {
+ detached = true;
+ }
}
public boolean isDestroyed() {
return destroyed;
}
+
+ public boolean isDetached() {
+ return detached;
+ }
@Override
public int hashCode() {