You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sa...@apache.org on 2006/03/15 23:28:22 UTC

svn commit: r386186 [1/2] - in /jakarta/commons/proper/pool/trunk: src/java/org/apache/commons/pool/ src/java/org/apache/commons/pool/impl/ src/test/org/apache/commons/pool/ src/test/org/apache/commons/pool/impl/ xdocs/

Author: sandymac
Date: Wed Mar 15 14:28:20 2006
New Revision: 386186

URL: http://svn.apache.org/viewcvs?rev=386186&view=rev
Log:
Created unit tests to verify KeyedObjectPools conform to new contracts.
Refactored KeyedObjectPool implementations to comply with new contracts.
Improved JavaDocs for KeyedObjectPools.

Added:
    jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java   (with props)
    jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java   (with props)
Modified:
    jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/BaseKeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/KeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/ObjectPool.java
    jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/StackKeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestKeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestObjectPool.java
    jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestStackKeyedObjectPool.java
    jakarta/commons/proper/pool/trunk/xdocs/changes.xml

Modified: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/BaseKeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/BaseKeyedObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/BaseKeyedObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/BaseKeyedObjectPool.java Wed Mar 15 14:28:20 2006
@@ -17,7 +17,7 @@
 package org.apache.commons.pool;
 
 /**
- * A simple base implementation of {@link ObjectPool}.
+ * A simple base implementation of <code>KeyedObjectPool</code>.
  * Optional operations are implemented to either do nothing, return a value
  * indicating it is unsupported or throw {@link UnsupportedOperationException}.
  *

Modified: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/KeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/KeyedObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/KeyedObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/KeyedObjectPool.java Wed Mar 15 14:28:20 2006
@@ -124,8 +124,8 @@
 
     /**
      * Create an object using the {@link KeyedPoolableObjectFactory factory} or other
-     * implementation dependent mechanism, passivated, and then placed in the idle object pool.
-     * addObject() is useful for "pre-loading" a pool with idle objects.
+     * implementation dependent mechanism, passivate it, and then place it in the idle object pool.
+     * <code>addObject</code> is useful for "pre-loading" a pool with idle objects
      * (Optional operation).
      *
      * @param key the key a new instance should be added to

Modified: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/ObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/ObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/ObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/ObjectPool.java Wed Mar 15 14:28:20 2006
@@ -112,8 +112,8 @@
 
     /**
      * Create an object using the {@link PoolableObjectFactory factory} or other
-     * implementation dependent mechanism, passivated, and then placed in the idle object pool.
-     * addObject() is useful for "pre-loading" a pool with idle objects.
+     * implementation dependent mechanism, passivate it, and then place it in the idle object pool.
+     * <code>addObject</code> is useful for "pre-loading" a pool with idle objects.
      * (Optional operation).
      *
      * @throws Exception when {@link PoolableObjectFactory#makeObject} fails.

Modified: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/GenericKeyedObjectPool.java Wed Mar 15 14:28:20 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2004,2006 The Apache Software Foundation.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,65 +32,65 @@
 import org.apache.commons.pool.KeyedPoolableObjectFactory;
 
 /**
- * A configurable {@link KeyedObjectPool} implementation.
+ * A configurable <code>KeyedObjectPool</code> implementation.
  * <p>
  * When coupled with the appropriate {@link KeyedPoolableObjectFactory},
- * <tt>GenericKeyedObjectPool</tt> provides robust pooling functionality for
+ * <code>GenericKeyedObjectPool</code> provides robust pooling functionality for
  * arbitrary objects.
- * <p>
- * A <tt>GenericKeyedObjectPool</tt> provides a number of configurable parameters:
+ * </p>
+ * <p>A <code>GenericKeyedObjectPool</code> provides a number of configurable parameters:</p>
  * <ul>
  *  <li>
- *    {@link #setMaxActive <i>maxActive</i>} controls the maximum number of objects (per key)
+ *    {@link #setMaxActive maxActive} controls the maximum number of objects (per key)
  *    that can be borrowed from the pool at one time.  When non-positive, there
  *    is no limit to the number of objects that may be active at one time.
- *    When {@link #setMaxActive <i>maxActive</i>} is exceeded, the pool is said to be exhausted.
+ *    When {@link #setMaxActive maxActive} is exceeded, the pool is said to be exhausted.
  *  </li>
  *  <li>
- *    {@link #setMaxIdle <i>maxIdle</i>} controls the maximum number of objects that can
+ *    {@link #setMaxIdle maxIdle} controls the maximum number of objects that can
  *    sit idle in the pool (per key) at any time.  When negative, there
  *    is no limit to the number of objects that may be idle at one time.
  *  </li>
  *  <li>
- *    {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} specifies the
- *    behaviour of the {@link #borrowObject} method when the pool is exhausted:
+ *    {@link #setWhenExhaustedAction whenExhaustedAction} specifies the
+ *    behaviour of the {@link #borrowObject borrowObject} method when the pool is exhausted:
  *    <ul>
  *    <li>
- *      When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} is
- *      {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject} will throw
+ *      When {@link #setWhenExhaustedAction whenExhaustedAction} is
+ *      {@link #WHEN_EXHAUSTED_FAIL}, {@link #borrowObject borrowObject} will throw
  *      a {@link NoSuchElementException}
  *    </li>
  *    <li>
- *      When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>} is
- *      {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject} will create a new
- *      object and return it(essentially making {@link #setMaxActive <i>maxActive</i>}
+ *      When {@link #setWhenExhaustedAction whenExhaustedAction} is
+ *      {@link #WHEN_EXHAUSTED_GROW}, {@link #borrowObject borrowObject} will create a new
+ *      object and return it (essentially making {@link #setMaxActive maxActive}
  *      meaningless.)
  *    </li>
  *    <li>
- *      When {@link #setWhenExhaustedAction <i>whenExhaustedAction</i>}
- *      is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject} will block
- *      (invoke {@link Object#wait} until a new or idle object is available.
- *      If a positive {@link #setMaxWait <i>maxWait</i>}
- *      value is supplied, the {@link #borrowObject} will block for at
+ *      When {@link #setWhenExhaustedAction whenExhaustedAction}
+ *      is {@link #WHEN_EXHAUSTED_BLOCK}, {@link #borrowObject borrowObject} will block
+ *      (invoke {@link Object#wait wait} until a new or idle object is available.
+ *      If a positive {@link #setMaxWait maxWait}
+ *      value is supplied, the {@link #borrowObject borrowObject} will block for at
  *      most that many milliseconds, after which a {@link NoSuchElementException}
- *      will be thrown.  If {@link #setMaxWait <i>maxWait</i>} is non-positive,
- *      the {@link #borrowObject} method will block indefinitely.
+ *      will be thrown.  If {@link #setMaxWait maxWait} is non-positive,
+ *      the {@link #borrowObject borrowObject} method will block indefinitely.
  *    </li>
  *    </ul>
  *  </li>
  *  <li>
- *    When {@link #setTestOnBorrow <i>testOnBorrow</i>} is set, the pool will
+ *    When {@link #setTestOnBorrow testOnBorrow} is set, the pool will
  *    attempt to validate each object before it is returned from the
- *    {@link #borrowObject} method. (Using the provided factory's
- *    {@link org.apache.commons.pool.PoolableObjectFactory#validateObject} method.)  Objects that fail
+ *    {@link #borrowObject borrowObject} method. (Using the provided factory's
+ *    {@link KeyedPoolableObjectFactory#validateObject validateObject} method.)  Objects that fail
  *    to validate will be dropped from the pool, and a different object will
  *    be borrowed.
  *  </li>
  *  <li>
- *    When {@link #setTestOnReturn <i>testOnReturn</i>} is set, the pool will
+ *    When {@link #setTestOnReturn testOnReturn} is set, the pool will
  *    attempt to validate each object before it is returned to the pool in the
- *    {@link #returnObject} method. (Using the provided factory's
- *    {@link org.apache.commons.pool.PoolableObjectFactory#validateObject}
+ *    {@link #returnObject returnObject} method. (Using the provided factory's
+ *    {@link KeyedPoolableObjectFactory#validateObject validateObject}
  *    method.)  Objects that fail to validate will be dropped from the pool.
  *  </li>
  * </ul>
@@ -101,31 +101,32 @@
  * following attributes:
  * <ul>
  *  <li>
- *   {@link #setTimeBetweenEvictionRunsMillis <i>timeBetweenEvictionRunsMillis</i>}
+ *   {@link #setTimeBetweenEvictionRunsMillis timeBetweenEvictionRunsMillis}
  *   indicates how long the eviction thread should sleep before "runs" of examining
  *   idle objects.  When non-positive, no eviction thread will be launched.
  *  </li>
  *  <li>
- *   {@link #setMinEvictableIdleTimeMillis <i>minEvictableIdleTimeMillis</i>}
+ *   {@link #setMinEvictableIdleTimeMillis minEvictableIdleTimeMillis}
  *   specifies the minimum amount of time that an object may sit idle in the pool
  *   before it is eligable for eviction due to idle time.  When non-positive, no object
  *   will be dropped from the pool due to idle time alone.
  *  </li>
  *  <li>
- *   {@link #setTestWhileIdle <i>testWhileIdle</i>} indicates whether or not idle
+ *   {@link #setTestWhileIdle testWhileIdle} indicates whether or not idle
  *   objects should be validated using the factory's
- *   {@link org.apache.commons.pool.PoolableObjectFactory#validateObject} method.  Objects
+ *   {@link KeyedPoolableObjectFactory#validateObject validateObject} method.  Objects
  *   that fail to validate will be dropped from the pool.
  *  </li>
  * </ul>
  * <p>
  * GenericKeyedObjectPool is not usable without a {@link KeyedPoolableObjectFactory}.  A
  * non-<code>null</code> factory must be provided either as a constructor argument
- * or via a call to {@link #setFactory} before the pool is used.
+ * or via a call to {@link #setFactory setFactory} before the pool is used.
  * </p>
  * @see GenericObjectPool
  * @author Rodney Waldhoff
  * @author Dirk Verbeeck
+ * @author Sandy McArthur
  * @version $Revision$ $Date$
  */
 public class GenericKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
@@ -216,7 +217,7 @@
      * @see #getTestOnBorrow
      * @see #setTestOnBorrow
      */
-    public static final boolean DEFAULT_TEST_ON_BORROW = false;
+    public static final boolean DEFAULT_TEST_ON_BORROW = true;
 
     /**
      * The default "test on return" value.
@@ -268,32 +269,35 @@
     //--- constructors -----------------------------------------------
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt>..
+     * Create a new <code>GenericKeyedObjectPool</code> with no factory.
+     *
+     * @see #GenericKeyedObjectPool(KeyedPoolableObjectFactory)
+     * @see #setFactory(KeyedPoolableObjectFactory)
      */
     public GenericKeyedObjectPool() {
         this(null,DEFAULT_MAX_ACTIVE,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      */
     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory) {
         this(factory,DEFAULT_MAX_ACTIVE,DEFAULT_WHEN_EXHAUSTED_ACTION,DEFAULT_MAX_WAIT,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
-     * @param config a non-<tt>null</tt> {@link GenericKeyedObjectPool.Config} describing my configuration
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
+     * @param config a non-<code>null</code> {@link GenericKeyedObjectPool.Config} describing the configuration
      */
     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, GenericKeyedObjectPool.Config config) {
         this(factory,config.maxActive,config.whenExhaustedAction,config.maxWait,config.maxIdle,config.maxTotal,config.testOnBorrow,config.testOnReturn,config.timeBetweenEvictionRunsMillis,config.numTestsPerEvictionRun,config.minEvictableIdleTimeMillis,config.testWhileIdle);
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      */
     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive) {
@@ -301,21 +305,21 @@
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
      */
     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait) {
         this(factory,maxActive,whenExhaustedAction,maxWait,DEFAULT_MAX_IDLE,DEFAULT_TEST_ON_BORROW,DEFAULT_TEST_ON_RETURN,DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS,DEFAULT_NUM_TESTS_PER_EVICTION_RUN,DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS,DEFAULT_TEST_WHILE_IDLE);
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
@@ -325,11 +329,11 @@
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
      * @param maxIdle the maximum number of idle objects in my pool (per key) (see {@link #setMaxIdle})
      */
     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle) {
@@ -337,11 +341,11 @@
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)KeyedPoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #getMaxWait})
      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
@@ -351,11 +355,11 @@
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
      * @param testOnReturn whether or not to validate objects after they are returned to the {@link #returnObject} method (see {@link #setTestOnReturn})
@@ -369,11 +373,11 @@
     }
 
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
      * @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
      * @param testOnBorrow whether or not to validate objects before they are returned by the {@link #borrowObject} method (see {@link #setTestOnBorrow})
@@ -384,15 +388,15 @@
      * @param testWhileIdle whether or not to validate objects in the idle object eviction thread, if any (see {@link #setTestWhileIdle})
      */
     public GenericKeyedObjectPool(KeyedPoolableObjectFactory factory, int maxActive, byte whenExhaustedAction, long maxWait, int maxIdle, int maxTotal, boolean testOnBorrow, boolean testOnReturn, long timeBetweenEvictionRunsMillis, int numTestsPerEvictionRun, long minEvictableIdleTimeMillis, boolean testWhileIdle) {
-        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, GenericKeyedObjectPool.DEFAULT_MAX_TOTAL, GenericKeyedObjectPool.DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
+        this(factory, maxActive, whenExhaustedAction, maxWait, maxIdle, maxTotal, GenericKeyedObjectPool.DEFAULT_MIN_IDLE, testOnBorrow, testOnReturn, timeBetweenEvictionRunsMillis, numTestsPerEvictionRun, minEvictableIdleTimeMillis, testWhileIdle);
     }
     
     /**
-     * Create a new <tt>GenericKeyedObjectPool</tt> using the specified values.
-     * @param factory the (possibly <tt>null</tt>)PoolableObjectFactory to use to create, validate and destroy objects
+     * Create a new <code>GenericKeyedObjectPool</code> using the specified values.
+     * @param factory the <code>KeyedPoolableObjectFactory</code> to use to create, validate, and destroy objects if not <code>null</code>
      * @param maxActive the maximum number of objects that can be borrowed from me at one time (per key) (see {@link #setMaxActive})
      * @param whenExhaustedAction the action to take when the pool is exhausted (see {@link #setWhenExhaustedAction})
-     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <i>whenExhaustedAction</i> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
+     * @param maxWait the maximum amount of time to wait for an idle object when the pool is exhausted an and <code>whenExhaustedAction</code> is {@link #WHEN_EXHAUSTED_BLOCK} (otherwise ignored) (see {@link #setMaxWait})
      * @param maxIdle the maximum number of idle objects in my pool (see {@link #setMaxIdle})
      * @param maxTotal the maximum number of objects that can exists at one time (see {@link #setMaxTotal})
      * @param minIdle the minimum number of idle objects to have in the pool at any one time (see {@link #setMinIdle})
@@ -588,7 +592,7 @@
     }
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * before being returned by the {@link #borrowObject}
      * method.  If the object fails to validate,
@@ -602,7 +606,7 @@
     }
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * before being returned by the {@link #borrowObject}
      * method.  If the object fails to validate,
@@ -616,7 +620,7 @@
     }
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * before being returned to the pool within the
      * {@link #returnObject}.
@@ -628,7 +632,7 @@
     }
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * before being returned to the pool within the
      * {@link #returnObject}.
@@ -679,8 +683,8 @@
      * Sets the number of objects to examine during each run of the
      * idle object evictor thread (if any).
      * <p>
-     * When a negative value is supplied, <tt>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</tt>
-     * tests will be run.  I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
+     * When a negative value is supplied, <code>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</code>
+     * tests will be run.  I.e., when the value is <code>-n</code>, roughly one <code>n</code>th of the
      * idle objects will be tested per run.
      *
      * @see #getNumTestsPerEvictionRun
@@ -717,7 +721,7 @@
     }
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * by the idle object evictor (if any).  If an object
      * fails to validate, it will be dropped from the pool.
@@ -730,7 +734,7 @@
     }
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * by the idle object evictor (if any).  If an object
      * fails to validate, it will be dropped from the pool.
@@ -764,6 +768,7 @@
     //-- ObjectPool methods ------------------------------------------
 
     public synchronized Object borrowObject(Object key) throws Exception {
+        assertOpen();
         long starttime = System.currentTimeMillis();
         boolean newlyCreated = false;
         for(;;) {
@@ -833,19 +838,48 @@
                     }
                 }
             }
-            _factory.activateObject(key,pair.value);
-            if(_testOnBorrow && !_factory.validateObject(key,pair.value)) {
-                _factory.destroyObject(key,pair.value);
-                if(newlyCreated) {
-                    throw new NoSuchElementException("Could not create a validated object");
-                } // else keep looping
-            } else {
+            if (newlyCreated) {
                 incrementActiveCount(key);
                 return pair.value;
+            } else {
+                try {
+                    _factory.activateObject(key, pair.value);
+                } catch (Exception e) {
+                    try {
+                        _factory.destroyObject(key,pair.value);
+                    } catch (Exception e2) {
+                        // swallowed
+                    }
+                    continue;
+                }
+
+                boolean invalid = true;
+                try {
+                    invalid = _testOnBorrow && !_factory.validateObject(key, pair.value);
+                } catch (Exception e) {
+                    // swallowed
+                }
+                if (invalid) {
+                    try {
+                        _factory.destroyObject(key,pair.value);
+                    } catch (Exception e) {
+                        // swallowed
+                    }
+                    if(newlyCreated) {
+                        throw new NoSuchElementException("Could not create a validated object");
+                    } // else keep looping
+                } else {
+                    incrementActiveCount(key);
+                    return pair.value;
+                }
+
             }
         }
     }
 
+    /**
+     * Clears the pool, removing all pooled instances.
+     */
     public synchronized void clear() {
         for(Iterator keyiter = _poolMap.keySet().iterator(); keyiter.hasNext(); ) {
             Object key = keyiter.next();
@@ -916,6 +950,11 @@
         notifyAll();
     }
 
+    /**
+     * Clears the specified pool, removing all pooled instances corresponding to the given <code>key</code>.
+     *
+     * @param key the key to clear
+     */
     public synchronized void clear(Object key) {
         LinkedList pool = (LinkedList)(_poolMap.remove(key));
         if(null == pool) {
@@ -934,18 +973,41 @@
         notifyAll();
     }
 
+    /**
+     * Returns the total number of instances current borrowed from this pool but not yet returned.
+     *
+     * @return the total number of instances currently borrowed from this pool
+     */
     public synchronized int getNumActive() {
         return _totalActive;
     }
 
+    /**
+     * Returns the total number of instances currently idle in this pool.
+     *
+     * @return the total number of instances currently idle in this pool
+     */
     public synchronized int getNumIdle() {
         return _totalIdle;
     }
 
+    /**
+     * Returns the number of instances currently borrowed from but not yet returned
+     * to the pool corresponding to the given <code>key</code>.
+     *
+     * @param key the key to query
+     * @return the number of instances corresponding to the given <code>key</code> currently borrowed in this pool
+     */
     public synchronized int getNumActive(Object key) {
         return getActiveCount(key);
     }
 
+    /**
+     * Returns the number of instances corresponding to the given <code>key</code> currently idle in this pool.
+     *
+     * @param key the key to query
+     * @return the number of instances corresponding to the given <code>key</code> currently idle in this pool
+     */
     public synchronized int getNumIdle(Object key) {
         try {
             return((LinkedList)(_poolMap.get(key))).size();
@@ -973,6 +1035,15 @@
             }
         }
 
+        if (isClosed()) {
+            try {
+                _factory.destroyObject(key, obj);
+            } catch(Exception e) {
+                // ignored
+            }
+            return;
+        }
+
         boolean shouldDestroy = false;
         // grab the pool (list) of objects associated with the given key
         LinkedList pool = (LinkedList) (_poolMap.get(key));
@@ -1004,24 +1075,67 @@
     public synchronized void invalidateObject(Object key, Object obj) throws Exception {
         try {
             _factory.destroyObject(key, obj);
-        }
-        finally {
+        } catch (Exception e) {
+            // swallowed
+        } finally {
             decrementActiveCount(key);
             notifyAll(); // _totalActive has changed
         }
     }
 
+    /**
+     * Create an object using the {@link KeyedPoolableObjectFactory#makeObject factory},
+     * passivate it, and then place it in the idle object pool.
+     * <code>addObject</code> is useful for "pre-loading" a pool with idle objects.
+     *
+     * @param key the key a new instance should be added to
+     * @throws Exception when {@link KeyedPoolableObjectFactory#makeObject} fails.
+     * @throws IllegalStateException when no {@link #setFactory factory} has been set or after {@link #close} has been called on this pool.
+     */
     public synchronized void addObject(Object key) throws Exception {
+        assertOpen();
+        if (_factory == null) {
+            throw new IllegalStateException("Cannot add objects without a factory.");
+        }
         Object obj = _factory.makeObject(key);
-        incrementActiveCount(key); // returnObject will decrement this
-        returnObject(key,obj);
+
+        // if we need to validate this object, do so
+        boolean success = true; // whether or not this object passed validation
+        if(_testOnReturn && !_factory.validateObject(key, obj)) {
+            success = false;
+            _factory.destroyObject(key, obj);
+        } else {
+            _factory.passivateObject(key, obj);
+        }
+
+        boolean shouldDestroy = false;
+        // grab the pool (list) of objects associated with the given key
+        LinkedList pool = (LinkedList) (_poolMap.get(key));
+        // if it doesn't exist, create it
+        if(null == pool) {
+            pool = new LinkedList();
+            _poolMap.put(key, pool);
+        }
+        // if there's no space in the pool, flag the object for destruction
+        // else if we passivated succesfully, return it to the pool
+        if(_maxIdle >= 0 && (pool.size() >= _maxIdle)) {
+            shouldDestroy = true;
+        } else if(success) {
+            pool.addLast(new ObjectTimestampPair(obj));
+            _totalIdle++;
+        }
+        notifyAll();
+
+        if(shouldDestroy) {
+            _factory.destroyObject(key, obj);
+        }
     }
 
     /**
      * Registers a key for pool control.
      *
-     * If <i>populateImmediately</i> is <code>true</code>, the pool will immediately commence
-     * a sustain cycle. If <i>populateImmediately</i> is <code>false</code>, the pool will be
+     * If <code>populateImmediately</code> is <code>true</code>, the pool will immediately commence
+     * a sustain cycle. If <code>populateImmediately</code> is <code>false</code>, the pool will be
      * populated when the next schedules sustain task is run.
      *
      * @param key - The key to register for pool control.
@@ -1048,16 +1162,15 @@
 
     public synchronized void close() throws Exception {
         clear();
-        _poolMap = null;
-        _activeMap = null;
-        _recentlyEvictedKeys = null;
-        if(null != _evictor) {
+        if (null != _evictor) {
             _evictor.cancel();
             _evictor = null;
         }
+        super.close();
     }
 
     public synchronized void setFactory(KeyedPoolableObjectFactory factory) throws IllegalStateException {
+        assertOpen();
         if(0 < getNumActive()) {
             throw new IllegalStateException("Objects are already active");
         } else {
@@ -1066,6 +1179,9 @@
         }
     }
 
+    /**
+     * Remove any idle object that meet the criteria for eviction.
+     */
     public synchronized void evict() throws Exception {
         Object key = null;
         if (_recentlyEvictedKeys == null) {
@@ -1138,7 +1254,7 @@
 
                             // Do not remove the key from the _poolList or _poolmap, even if the list
                             // stored in the _poolMap for this key is empty when the
-                            // {@link #getMinIdle <i>minIdle</i>} is > 0.
+                            // {@link #getMinIdle <code>minIdle</code>} is > 0.
                             //
                             // Otherwise if it was the last object for that key, drop that pool
                             if ((_minIdle == 0) && (((LinkedList)(_poolMap.get(key))).isEmpty())) {
@@ -1207,7 +1323,7 @@
 
     /**
      * Start the eviction thread or service, or when
-     * <i>delay</i> is non-positive, stop it
+     * <code>delay</code> is non-positive, stop it
      * if it is already running.
      */
     protected synchronized void startEvictor(long delay) {
@@ -1362,7 +1478,7 @@
 
     /**
      * A simple "struct" encapsulating the
-     * configuration information for a {@link GenericKeyedObjectPool}.
+     * configuration information for a <code>GenericKeyedObjectPool</code>.
      * @see GenericKeyedObjectPool#GenericKeyedObjectPool(KeyedPoolableObjectFactory,GenericKeyedObjectPool.Config)
      * @see GenericKeyedObjectPool#setConfig
      */
@@ -1444,7 +1560,7 @@
     private byte _whenExhaustedAction = DEFAULT_WHEN_EXHAUSTED_ACTION;
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * before being returned by the {@link #borrowObject}
      * method.  If the object fails to validate,
@@ -1457,7 +1573,7 @@
     private boolean _testOnBorrow = DEFAULT_TEST_ON_BORROW;
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * before being returned to the pool within the
      * {@link #returnObject}.
@@ -1468,7 +1584,7 @@
     private boolean _testOnReturn = DEFAULT_TEST_ON_RETURN;
 
     /**
-     * When <tt>true</tt>, objects will be
+     * When <code>true</code>, objects will be
      * {@link org.apache.commons.pool.PoolableObjectFactory#validateObject validated}
      * by the idle object evictor (if any).  If an object
      * fails to validate, it will be dropped from the pool.
@@ -1495,8 +1611,8 @@
      * The number of objects to examine during each run of the
      * idle object evictor thread (if any).
      * <p>
-     * When a negative value is supplied, <tt>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</tt>
-     * tests will be run.  I.e., when the value is <i>-n</i>, roughly one <i>n</i>th of the
+     * When a negative value is supplied, <code>ceil({@link #getNumIdle})/abs({@link #getNumTestsPerEvictionRun})</code>
+     * tests will be run.  I.e., when the value is <code>-n</code>, roughly one <code>n</code>th of the
      * idle objects will be tested per run.
      *
      * @see #setNumTestsPerEvictionRun

Modified: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/StackKeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/StackKeyedObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/StackKeyedObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/impl/StackKeyedObjectPool.java Wed Mar 15 14:28:20 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2004,2006 The Apache Software Foundation.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,17 +16,17 @@
 
 package org.apache.commons.pool.impl;
 
+import org.apache.commons.pool.BaseKeyedObjectPool;
+import org.apache.commons.pool.KeyedObjectPool;
+import org.apache.commons.pool.KeyedPoolableObjectFactory;
+
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 import java.util.Stack;
 
-import org.apache.commons.pool.BaseKeyedObjectPool;
-import org.apache.commons.pool.KeyedObjectPool;
-import org.apache.commons.pool.KeyedPoolableObjectFactory;
-
 /**
- * A simple, {@link java.util.Stack Stack}-based {@link KeyedObjectPool} implementation.
+ * A simple, <code>Stack</code>-based <code>KeyedObjectPool</code> implementation.
  * <p>
  * Given a {@link KeyedPoolableObjectFactory}, this class will maintain
  * a simple pool of instances.  A finite number of "sleeping"
@@ -34,52 +34,62 @@
  * empty, new instances are created to support the new load.
  * Hence this class places no limit on the number of "active"
  * instances created by the pool, but is quite useful for
- * re-using <tt>Object</tt>s without introducing
+ * re-using <code>Object</code>s without introducing
  * artificial limits.
+ * </p>
  *
  * @author Rodney Waldhoff
- * @version $Revision$ $Date$ 
+ * @author Sandy McArthur
+ * @version $Revision$ $Date$
+ * @see Stack
  */
 public class StackKeyedObjectPool extends BaseKeyedObjectPool implements KeyedObjectPool {
     /**
-     * Create a new pool using
-     * no factory. Clients must first populate the pool
-     * using {@link #returnObject(java.lang.Object,java.lang.Object)}
-     * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
+     * Create a new pool using no factory.
+     * Clients must first set the {@link #setFactory factory} or
+     * may populate the pool using {@link #returnObject returnObject}
+     * before they can be {@link #borrowObject borrowed}.
+     *
+     * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory)
+     * @see #setFactory(KeyedPoolableObjectFactory)
      */
     public StackKeyedObjectPool() {
         this((KeyedPoolableObjectFactory)null,DEFAULT_MAX_SLEEPING,DEFAULT_INIT_SLEEPING_CAPACITY);
     }
 
     /**
-     * Create a new pool using
-     * no factory. Clients must first populate the pool
-     * using {@link #returnObject(java.lang.Object,java.lang.Object)}
-     * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
+     * Create a new pool using no factory.
+     * Clients must first set the {@link #setFactory factory} or
+     * may populate the pool using {@link #returnObject returnObject}
+     * before they can be {@link #borrowObject borrowed}.
      *
      * @param max cap on the number of "sleeping" instances in the pool
+     * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory, int)
+     * @see #setFactory(KeyedPoolableObjectFactory)
      */
     public StackKeyedObjectPool(int max) {
         this((KeyedPoolableObjectFactory)null,max,DEFAULT_INIT_SLEEPING_CAPACITY);
     }
 
     /**
-     * Create a new pool using
-     * no factory. Clients must first populate the pool
-     * using {@link #returnObject(java.lang.Object,java.lang.Object)}
-     * before they can be {@link #borrowObject(java.lang.Object) borrowed}.
+     * Create a new pool using no factory.
+     * Clients must first set the {@link #setFactory factory} or
+     * may populate the pool using {@link #returnObject returnObject}
+     * before they can be {@link #borrowObject borrowed}.
      *
      * @param max cap on the number of "sleeping" instances in the pool
      * @param init initial size of the pool (this specifies the size of the container,
      *             it does not cause the pool to be pre-populated.)
+     * @see #StackKeyedObjectPool(KeyedPoolableObjectFactory, int, int)
+     * @see #setFactory(KeyedPoolableObjectFactory)
      */
     public StackKeyedObjectPool(int max, int init) {
         this((KeyedPoolableObjectFactory)null,max,init);
     }
 
     /**
-     * Create a new <tt>SimpleKeyedObjectPool</tt> using
-     * the specified <i>factory</i> to create new instances.
+     * Create a new <code>SimpleKeyedObjectPool</code> using
+     * the specified <code>factory</code> to create new instances.
      *
      * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
      */
@@ -88,9 +98,9 @@
     }
 
     /**
-     * Create a new <tt>SimpleKeyedObjectPool</tt> using
-     * the specified <i>factory</i> to create new instances.
-     * capping the number of "sleeping" instances to <i>max</i>
+     * Create a new <code>SimpleKeyedObjectPool</code> using
+     * the specified <code>factory</code> to create new instances.
+     * capping the number of "sleeping" instances to <code>max</code>
      *
      * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
      * @param max cap on the number of "sleeping" instances in the pool
@@ -100,11 +110,11 @@
     }
 
     /**
-     * Create a new <tt>SimpleKeyedObjectPool</tt> using
-     * the specified <i>factory</i> to create new instances.
-     * capping the number of "sleeping" instances to <i>max</i>,
+     * Create a new <code>SimpleKeyedObjectPool</code> using
+     * the specified <code>factory</code> to create new instances.
+     * capping the number of "sleeping" instances to <code>max</code>,
      * and initially allocating a container capable of containing
-     * at least <i>init</i> instances.
+     * at least <code>init</code> instances.
      *
      * @param factory the {@link KeyedPoolableObjectFactory} used to populate the pool
      * @param max cap on the number of "sleeping" instances in the pool
@@ -120,88 +130,203 @@
     }
 
     public synchronized Object borrowObject(Object key) throws Exception {
-        Object obj = null;
+        assertOpen();
         Stack stack = (Stack)(_pools.get(key));
         if(null == stack) {
             stack = new Stack();
             stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
             _pools.put(key,stack);
         }
-        try {
-            obj = stack.pop();
-            _totIdle--;
-        } catch(Exception e) {
-            if(null == _factory) {
-                throw new NoSuchElementException();
+        Object obj = null;
+        do {
+            boolean newlyMade = false;
+            // TODO: Don't use exception, test size.
+            if (!stack.empty()) {
+                obj = stack.pop();
+                _totIdle--;
             } else {
-                obj = _factory.makeObject(key);
+                if(null == _factory) {
+                    throw new NoSuchElementException("pools without a factory cannot create new objects as needed.");
+                } else {
+                    obj = _factory.makeObject(key);
+                    newlyMade = true;
+                }
             }
-        }
-        if(null != obj && null != _factory) {
-            _factory.activateObject(key,obj);
-        }
+            if(!newlyMade && null != obj && null != _factory) {
+                try {
+                    _factory.activateObject(key, obj);
+                    if (!_factory.validateObject(key, obj)) {
+                        try {
+                            _factory.destroyObject(key, obj);
+                        } catch (Exception e2) {
+                            // swallowed
+                        }
+                        obj = null;
+                    }
+                } catch (Exception e) {
+                    try {
+                        _factory.destroyObject(key, obj);
+                    } catch (Exception e2) {
+                        // swallowed
+                    }
+                    obj = null;
+                }
+            }
+        } while (obj == null);
         incrementActiveCount(key);
         return obj;
     }
 
     public synchronized void returnObject(Object key, Object obj) throws Exception {
         decrementActiveCount(key);
-        if(null == _factory || _factory.validateObject(key,obj)) {
-            Stack stack = (Stack)(_pools.get(key));
-            if(null == stack) {
-                stack = new Stack();
-                stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
-                _pools.put(key,stack);
+        if (null != _factory) {
+            try {
+                _factory.passivateObject(key, obj);
+            } catch (Exception e) {
+                try {
+                    _factory.destroyObject(key, obj);
+                } catch (Exception e2) {
+                    // swallowed
+                }
+                return;
             }
-            if(null != _factory) {
+        }
+
+        if (isClosed()) {
+            if (null != _factory) {
                 try {
-                    _factory.passivateObject(key,obj);
-                } catch(Exception e) {
-                    _factory.destroyObject(key,obj);
-                    return;
+                    _factory.destroyObject(key, obj);
+                } catch (Exception e) {
+                    // swallowed
                 }
             }
-            if(stack.size() < _maxSleeping) {
-                stack.push(obj);
-                _totIdle++;
+            return;
+        }
+
+        Stack stack = (Stack)_pools.get(key);
+        if(null == stack) {
+            stack = new Stack();
+            stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
+            _pools.put(key,stack);
+        }
+        final int stackSize = stack.size();
+        if (stackSize >= _maxSleeping) {
+            final Object staleObj;
+            if (stackSize > 0) {
+                staleObj = stack.remove(0);
+                _totIdle--;
             } else {
-                if(null != _factory) {
-                    _factory.destroyObject(key,obj);
-                }
+                staleObj = obj;
             }
-        } else {
             if(null != _factory) {
-                _factory.destroyObject(key,obj);
+                try {
+                    _factory.destroyObject(key, staleObj);
+                } catch (Exception e) {
+                    // swallowed
+                }
             }
         }
+        stack.push(obj);
+        _totIdle++;
     }
 
     public synchronized void invalidateObject(Object key, Object obj) throws Exception {
         decrementActiveCount(key);
         if(null != _factory) {
+            try {
             _factory.destroyObject(key,obj);
+            } catch (Exception e) {
+                // swallowed
+            }
         }
         notifyAll(); // _totalActive has changed
     }
 
+    /**
+     * Create an object using the {@link KeyedPoolableObjectFactory#makeObject factory},
+     * passivate it, and then placed in the idle object pool.
+     * <code>addObject</code> is useful for "pre-loading" a pool with idle objects.
+     *
+     * @param key the key a new instance should be added to
+     * @throws Exception when {@link KeyedPoolableObjectFactory#makeObject} fails.
+     * @throws IllegalStateException when no {@link #setFactory factory} has been set or after {@link #close} has been called on this pool.
+     */
     public synchronized void addObject(Object key) throws Exception {
+        assertOpen();
+        if (_factory == null) {
+            throw new IllegalStateException("Cannot add objects without a factory.");
+        }
         Object obj = _factory.makeObject(key);
-        incrementActiveCount(key); // returnObject will decrement this
-        returnObject(key,obj);
+
+        _factory.passivateObject(key, obj);
+
+        Stack stack = (Stack)_pools.get(key);
+        if(null == stack) {
+            stack = new Stack();
+            stack.ensureCapacity( _initSleepingCapacity > _maxSleeping ? _maxSleeping : _initSleepingCapacity);
+            _pools.put(key,stack);
+        }
+
+        final int stackSize = stack.size();
+        if (stackSize >= _maxSleeping) {
+            final Object staleObj;
+            if (stackSize > 0) {
+                staleObj = stack.remove(0);
+                _totIdle--;
+            } else {
+                staleObj = obj;
+            }
+            if(null != _factory) {
+                try {
+                    _factory.destroyObject(key, staleObj);
+                } catch (Exception e) {
+                    // Don't swallow destroying the newly created object.
+                    if (obj == staleObj) {
+                        throw e;
+                    }
+                }
+            }
+        } else {
+            stack.push(obj);
+            _totIdle++;
+        }
     }
 
+    /**
+     * Returns the total number of instances currently idle in this pool.
+     *
+     * @return the total number of instances currently idle in this pool
+     */
     public int getNumIdle() {
         return _totIdle;
     }
 
+    /**
+     * Returns the total number of instances current borrowed from this pool but not yet returned.
+     *
+     * @return the total number of instances currently borrowed from this pool
+     */
     public int getNumActive() {
         return _totActive;
     }
 
+    /**
+     * Returns the number of instances currently borrowed from but not yet returned
+     * to the pool corresponding to the given <code>key</code>.
+     *
+     * @param key the key to query
+     * @return the number of instances corresponding to the given <code>key</code> currently borrowed in this pool
+     */
     public synchronized int getNumActive(Object key) {
         return getActiveCount(key);
     }
 
+    /**
+     * Returns the number of instances corresponding to the given <code>key</code> currently idle in this pool.
+     *
+     * @param key the key to query
+     * @return the number of instances corresponding to the given <code>key</code> currently idle in this pool
+     */
     public synchronized int getNumIdle(Object key) {
         try {
             return((Stack)(_pools.get(key))).size();
@@ -210,6 +335,9 @@
         }
     }
 
+    /**
+     * Clears the pool, removing all pooled instances.
+     */
     public synchronized void clear() {
         Iterator it = _pools.keySet().iterator();
         while(it.hasNext()) {
@@ -222,6 +350,11 @@
         _activeCount.clear();
     }
 
+    /**
+     * Clears the specified pool, removing all pooled instances corresponding to the given <code>key</code>.
+     *
+     * @param key the key to clear
+     */
     public synchronized void clear(Object key) {
         Stack stack = (Stack)(_pools.remove(key));
         destroyStack(key,stack);
@@ -261,13 +394,29 @@
         return buf.toString();
     }
 
+    /**
+     * Close this pool, and free any resources associated with it.
+     * <p>
+     * Calling {@link #addObject addObject} or {@link #borrowObject borrowObject} after invoking
+     * this method on a pool will cause them to throw an {@link IllegalStateException}.
+     * </p>
+     *
+     * @throws Exception <strong>deprecated</strong>: implementations should silently fail if not all resources can be freed.
+     */
     public synchronized void close() throws Exception {
         clear();
-        _pools = null;
-        _factory = null;
-        _activeCount = null;
+        super.close();
     }
 
+    /**
+     * Sets the {@link KeyedPoolableObjectFactory factory} the pool uses
+     * to create new instances.
+     * Trying to change the <code>factory</code> after a pool has been used will frequently
+     * throw an {@link UnsupportedOperationException}.
+     *
+     * @param factory the {@link KeyedPoolableObjectFactory} used to create new instances.
+     * @throws IllegalStateException when the factory cannot be set at this time
+     */
     public synchronized void setFactory(KeyedPoolableObjectFactory factory) throws IllegalStateException {
         if(0 < getNumActive()) {
             throw new IllegalStateException("Objects are already active");
@@ -325,7 +474,7 @@
     /** My {@link KeyedPoolableObjectFactory}. */
     protected KeyedPoolableObjectFactory _factory = null;
 
-    /** The cap on the number of "sleeping" instances in <i>each</i> pool. */
+    /** The cap on the number of "sleeping" instances in <code>each</code> pool. */
     protected int _maxSleeping = DEFAULT_MAX_SLEEPING;
 
     /** The initial capacity of each pool. */

Added: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java?rev=386186&view=auto
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java (added)
+++ jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java Wed Mar 15 14:28:20 2006
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.pool;
+
+import java.util.List;
+import java.util.Collections;
+import java.util.Arrays;
+
+/**
+ * Holds method names, parameters, and return values for tracing method calls.
+ *
+ * @author Sandy McArthur
+ * @version $Revision$ $Date$
+ */
+class MethodCall {
+    private final String name;
+    private final List params;
+    private Object returned;
+
+    MethodCall(final String name) {
+        this(name, null);
+    }
+
+    MethodCall(final String name, final Object param) {
+        this(name, Collections.singletonList(param));
+    }
+
+    MethodCall(final String name, final Object param1, final Object param2) {
+        this(name, Arrays.asList(new Object[] {param1, param2}));
+    }
+
+    MethodCall(final String name, final List params) {
+        if (name == null) {
+            throw new IllegalArgumentException("name must not be null.");
+        }
+        this.name = name;
+        if (params != null) {
+            this.params = params;
+        } else {
+            this.params = Collections.EMPTY_LIST;
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List getParams() {
+        return params;
+    }
+
+    public Object getReturned() {
+        return returned;
+    }
+
+    public void setReturned(final Object returned) {
+        this.returned = returned;
+    }
+
+    public MethodCall returned(Object obj) {
+        setReturned(obj);
+        return this;
+    }
+
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        final MethodCall that = (MethodCall)o;
+
+        if (name != null ? !name.equals(that.name) : that.name != null) return false;
+        if (params != null ? !params.equals(that.params) : that.params != null) return false;
+        if (returned != null ? !returned.equals(that.returned) : that.returned != null) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = (name != null ? name.hashCode() : 0);
+        result = 29 * result + (params != null ? params.hashCode() : 0);
+        result = 29 * result + (returned != null ? returned.hashCode() : 0);
+        return result;
+    }
+
+    public String toString() {
+        final StringBuffer sb = new StringBuffer();
+        sb.append("MethodCall");
+        sb.append("{name='").append(name).append('\'');
+        if (!params.isEmpty()) {
+            sb.append(", params=").append(params);
+        }
+        if (returned != null) {
+            sb.append(", returned=").append(returned);
+        }
+        sb.append('}');
+        return sb.toString();
+    }
+}

Propchange: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/MethodCall.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java?rev=386186&view=auto
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java (added)
+++ jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java Wed Mar 15 14:28:20 2006
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.pool;
+
+/**
+ * An exception that only is thrown by this test.
+ */
+class PrivateException extends RuntimeException {
+    PrivateException(final String message) {
+        super(message);
+    }
+}

Propchange: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/PrivateException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestKeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestKeyedObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestKeyedObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestKeyedObjectPool.java Wed Mar 15 14:28:20 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2004,2006 The Apache Software Foundation.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,9 +17,13 @@
 
 import junit.framework.TestCase;
 
+import java.util.List;
+import java.util.ArrayList;
+
 /**
  * Abstract {@link TestCase} for {@link ObjectPool} implementations.
  * @author Rodney Waldhoff
+ * @author Sandy McArthur
  * @version $Revision$ $Date$
  */
 public abstract class TestKeyedObjectPool extends TestCase {
@@ -27,7 +31,7 @@
         super(testName);
     }
 
-    /** 
+    /**
      * Create an {@link KeyedObjectPool} instance
      * that can contain at least <i>mincapacity</i>
      * idle and active objects, or
@@ -37,6 +41,14 @@
     protected abstract KeyedObjectPool makeEmptyPool(int mincapacity);
 
     /**
+     * Create an <code>KeyedObjectPool</code> with the specified factory.
+     * The pool should be in a default configuration and conform to the expected
+     * behaviors described in {@link KeyedObjectPool}.
+     * Generally speaking there should be no limits on the various object counts.
+     */
+    protected abstract KeyedObjectPool makeEmptyPool(KeyedPoolableObjectFactory factory);
+
+    /**
      * Return what we expect to be the n<sup>th</sup>
      * object (zero indexed) created by the pool
      * for the given key.
@@ -44,26 +56,24 @@
     protected abstract Object getNthObject(Object key, int n);
 
     protected abstract Object makeKey(int n);
-    
+
     /**
      * Is the implementations LIFO?
-     * @return
      */
     protected abstract boolean isLifo();
-    
+
     /**
      * Is the implementationn FIFO?
-     * @return
      */
     protected abstract boolean isFifo();
 
     public void setUp() throws Exception {
     }
-    
+
     public void tearDown() throws Exception {
         _pool = null;
     }
-    
+
     public void testBaseBorrow() throws Exception {
         try {
             _pool = makeEmptyPool(3);
@@ -138,7 +148,7 @@
         _pool.returnObject(keya,obj0);
         assertEquals(0,_pool.getNumActive(keya));
         assertEquals(2,_pool.getNumIdle(keya));
-        
+
         assertEquals(0,_pool.getNumActive("xyzzy12345"));
         assertEquals(0,_pool.getNumIdle("xyzzy12345"));
     }
@@ -277,5 +287,377 @@
         }
     }
 
+    private final String KEY = "key";
+
+    public void testClosedPoolBehavior() throws Exception {
+        final KeyedObjectPool pool = makeEmptyPool(new BaseKeyedPoolableObjectFactory() {
+            public Object makeObject(final Object key) throws Exception {
+                return new Object();
+            }
+        });
+        Object o1 = pool.borrowObject(KEY);
+        Object o2 = pool.borrowObject(KEY);
+
+        pool.close();
+
+        try {
+            pool.addObject(KEY);
+            fail("A closed pool must throw an IllegalStateException when addObject is called.");
+        } catch (IllegalStateException ise) {
+            // expected
+        }
+
+        try {
+            pool.borrowObject(KEY);
+            fail("A closed pool must throw an IllegalStateException when borrowObject is called.");
+        } catch (IllegalStateException ise) {
+            // expected
+        }
+
+        // The following should not throw exceptions just because the pool is closed.
+        assertEquals("A closed pool shouldn't have any idle objects.", 0, pool.getNumIdle(KEY));
+        assertEquals("A closed pool shouldn't have any idle objects.", 0, pool.getNumIdle());
+        pool.getNumActive();
+        pool.getNumActive(KEY);
+        pool.returnObject(KEY, o1);
+        assertEquals("returnObject should not add items back into the idle object pool for a closed pool.", 0, pool.getNumIdle(KEY));
+        assertEquals("returnObject should not add items back into the idle object pool for a closed pool.", 0, pool.getNumIdle());
+        pool.invalidateObject(KEY, o2);
+        pool.clear(KEY);
+        pool.clear();
+        pool.close();
+    }
+
+    private final Integer ZERO = new Integer(0);
+    private final Integer ONE = new Integer(1);
+
+    public void testKPOFAddObjectUsage() throws Exception {
+        final FailingKeyedPoolableObjectFactory factory = new FailingKeyedPoolableObjectFactory();
+        final KeyedObjectPool pool = makeEmptyPool(factory);
+        final List expectedMethods = new ArrayList();
+
+        // addObject should make a new object, pasivate it and put it in the pool
+        pool.addObject(KEY);
+        expectedMethods.add(new MethodCall("makeObject", KEY).returned(ZERO));
+        expectedMethods.add(new MethodCall("passivateObject", KEY, ZERO));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+
+        //// Test exception handling of addObject
+        reset(pool, factory, expectedMethods);
+
+        // makeObject Exceptions should be propagated to client code from addObject
+        factory.setMakeObjectFail(true);
+        try {
+            pool.addObject(KEY);
+            fail("Expected addObject to propagate makeObject exception.");
+        } catch (PrivateException pe) {
+            // expected
+        }
+        expectedMethods.add(new MethodCall("makeObject", KEY));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+
+        clear(factory, expectedMethods);
+
+        // passivateObject Exceptions should be propagated to client code from addObject
+        factory.setMakeObjectFail(false);
+        factory.setPassivateObjectFail(true);
+        try {
+            pool.addObject(KEY);
+            fail("Expected addObject to propagate passivateObject exception.");
+        } catch (PrivateException pe) {
+            // expected
+        }
+        expectedMethods.add(new MethodCall("makeObject", KEY).returned(ONE));
+        expectedMethods.add(new MethodCall("passivateObject", KEY, ONE));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+    }
+
+    public void testKPOFBorrowObjectUsages() throws Exception {
+        final FailingKeyedPoolableObjectFactory factory = new FailingKeyedPoolableObjectFactory();
+        final KeyedObjectPool pool = makeEmptyPool(factory);
+        final List expectedMethods = new ArrayList();
+        Object obj;
+
+        /// Test correct behavior code paths
+
+        // existing idle object should be activated and validated
+        pool.addObject(KEY);
+        clear(factory, expectedMethods);
+        obj = pool.borrowObject(KEY);
+        expectedMethods.add(new MethodCall("activateObject", KEY, ZERO));
+        expectedMethods.add(new MethodCall("validateObject", KEY, ZERO).returned(Boolean.TRUE));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+        pool.returnObject(KEY, obj);
+
+        //// Test exception handling of borrowObject
+        reset(pool, factory, expectedMethods);
+
+        // makeObject Exceptions should be propagated to client code from borrowObject
+        factory.setMakeObjectFail(true);
+        try {
+            obj = pool.borrowObject(KEY);
+            fail("Expected borrowObject to propagate makeObject exception.");
+        } catch (PrivateException pe) {
+            // expected
+        }
+        expectedMethods.add(new MethodCall("makeObject", KEY));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+
+
+        // when activateObject fails in borrowObject, a new object should be borrowed/created
+        reset(pool, factory, expectedMethods);
+        pool.addObject(KEY);
+        clear(factory, expectedMethods);
+
+        factory.setActivateObjectFail(true);
+        expectedMethods.add(new MethodCall("activateObject", KEY, obj));
+        obj = pool.borrowObject(KEY);
+        expectedMethods.add(new MethodCall("makeObject", KEY).returned(ONE));
+        TestObjectPool.removeDestroyObjectCall(factory.getMethodCalls()); // The exact timing of destroyObject is flexible here.
+        assertEquals(expectedMethods, factory.getMethodCalls());
+        pool.returnObject(KEY, obj);
+
+        // when validateObject fails in borrowObject, a new object should be borrowed/created
+        reset(pool, factory, expectedMethods);
+        pool.addObject(KEY);
+        clear(factory, expectedMethods);
+
+        factory.setValidateObjectFail(true);
+        expectedMethods.add(new MethodCall("activateObject", KEY, ZERO));
+        expectedMethods.add(new MethodCall("validateObject", KEY, ZERO));
+        obj = pool.borrowObject(KEY);
+        expectedMethods.add(new MethodCall("makeObject", KEY).returned(ONE));
+        TestObjectPool.removeDestroyObjectCall(factory.getMethodCalls()); // The exact timing of destroyObject is flexible here.
+        assertEquals(expectedMethods, factory.getMethodCalls());
+        pool.returnObject(KEY, obj);
+    }
+
+    public void testKPOFReturnObjectUsages() throws Exception {
+        final FailingKeyedPoolableObjectFactory factory = new FailingKeyedPoolableObjectFactory();
+        final KeyedObjectPool pool = makeEmptyPool(factory);
+        final List expectedMethods = new ArrayList();
+        Object obj;
+        int idleCount;
+
+        /// Test correct behavior code paths
+        obj = pool.borrowObject(KEY);
+        clear(factory, expectedMethods);
+
+        // returned object should be passivated
+        pool.returnObject(KEY, obj);
+        expectedMethods.add(new MethodCall("passivateObject", KEY, obj));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+
+        //// Test exception handling of returnObject
+        reset(pool, factory, expectedMethods);
+
+        // passivateObject should swallow exceptions and not add the object to the pool
+        idleCount = pool.getNumIdle();
+        obj = pool.borrowObject(KEY);
+        clear(factory, expectedMethods);
+        factory.setPassivateObjectFail(true);
+        pool.returnObject(KEY, obj);
+        expectedMethods.add(new MethodCall("passivateObject", KEY, obj));
+        TestObjectPool.removeDestroyObjectCall(factory.getMethodCalls()); // The exact timing of destroyObject is flexible here.
+        assertEquals(expectedMethods, factory.getMethodCalls());
+        assertEquals(idleCount, pool.getNumIdle());
+
+        // destroyObject should swallow exceptions too
+        reset(pool, factory, expectedMethods);
+        obj = pool.borrowObject(KEY);
+        clear(factory, expectedMethods);
+        factory.setPassivateObjectFail(true);
+        factory.setDestroyObjectFail(true);
+        pool.returnObject(KEY, obj);
+    }
+
+    public void testKPOFInvalidateObjectUsages() throws Exception {
+        final FailingKeyedPoolableObjectFactory factory = new FailingKeyedPoolableObjectFactory();
+        final KeyedObjectPool pool = makeEmptyPool(factory);
+        final List expectedMethods = new ArrayList();
+        Object obj;
+
+        /// Test correct behavior code paths
+
+        obj = pool.borrowObject(KEY);
+        clear(factory, expectedMethods);
+
+        // invalidated object should be destroyed
+        pool.invalidateObject(KEY, obj);
+        expectedMethods.add(new MethodCall("destroyObject", KEY, obj));
+        assertEquals(expectedMethods, factory.getMethodCalls());
+
+        //// Test exception handling of invalidateObject
+        reset(pool, factory, expectedMethods);
+        obj = pool.borrowObject(KEY);
+        clear(factory, expectedMethods);
+        factory.setDestroyObjectFail(true);
+        pool.invalidateObject(KEY, obj);
+        Thread.sleep(250); // could be defered
+        TestObjectPool.removeDestroyObjectCall(factory.getMethodCalls());
+        assertEquals(expectedMethods, factory.getMethodCalls());
+    }
+
+    public void testKPOFClearUsages() throws Exception {
+        final FailingKeyedPoolableObjectFactory factory = new FailingKeyedPoolableObjectFactory();
+        final KeyedObjectPool pool = makeEmptyPool(factory);
+        final List expectedMethods = new ArrayList();
+
+        /// Test correct behavior code paths
+        PoolUtils.prefill(pool, KEY, 5);
+        pool.clear();
+
+        //// Test exception handling clear should swallow destory object failures
+        reset(pool, factory, expectedMethods);
+        factory.setDestroyObjectFail(true);
+        PoolUtils.prefill(pool, KEY, 5);
+        pool.clear();
+    }
+
+    public void testKPOFCloseUsages() throws Exception {
+        final FailingKeyedPoolableObjectFactory factory = new FailingKeyedPoolableObjectFactory();
+        KeyedObjectPool pool = makeEmptyPool(factory);
+        final List expectedMethods = new ArrayList();
+
+        /// Test correct behavior code paths
+        PoolUtils.prefill(pool, KEY, 5);
+        pool.close();
+
+
+        //// Test exception handling close should swallow failures
+        pool = makeEmptyPool(factory);
+        reset(pool, factory, expectedMethods);
+        factory.setDestroyObjectFail(true);
+        PoolUtils.prefill(pool, KEY, 5);
+        pool.close();
+    }
+
+    private void reset(final KeyedObjectPool pool, final FailingKeyedPoolableObjectFactory factory, final List expectedMethods) throws Exception {
+        pool.clear();
+        clear(factory, expectedMethods);
+        factory.reset();
+    }
+
+    private void clear(final FailingKeyedPoolableObjectFactory factory, final List expectedMethods) {
+        factory.getMethodCalls().clear();
+        expectedMethods.clear();
+    }
+
     private KeyedObjectPool _pool = null;
+
+    private static class FailingKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory {
+        private final List methodCalls = new ArrayList();
+        private int count = 0;
+        private boolean makeObjectFail;
+        private boolean activateObjectFail;
+        private boolean validateObjectFail;
+        private boolean passivateObjectFail;
+        private boolean destroyObjectFail;
+
+        public void reset() {
+            count = 0;
+            getMethodCalls().clear();
+            setMakeObjectFail(false);
+            setActivateObjectFail(false);
+            setValidateObjectFail(false);
+            setPassivateObjectFail(false);
+            setDestroyObjectFail(false);
+        }
+
+        public List getMethodCalls() {
+            return methodCalls;
+        }
+
+        public int getCurrentCount() {
+            return count;
+        }
+
+        public void setCurrentCount(final int count) {
+            this.count = count;
+        }
+
+        public boolean isMakeObjectFail() {
+            return makeObjectFail;
+        }
+
+        public void setMakeObjectFail(boolean makeObjectFail) {
+            this.makeObjectFail = makeObjectFail;
+        }
+
+        public boolean isDestroyObjectFail() {
+            return destroyObjectFail;
+        }
+
+        public void setDestroyObjectFail(boolean destroyObjectFail) {
+            this.destroyObjectFail = destroyObjectFail;
+        }
+
+        public boolean isValidateObjectFail() {
+            return validateObjectFail;
+        }
+
+        public void setValidateObjectFail(boolean validateObjectFail) {
+            this.validateObjectFail = validateObjectFail;
+        }
+
+        public boolean isActivateObjectFail() {
+            return activateObjectFail;
+        }
+
+        public void setActivateObjectFail(boolean activateObjectFail) {
+            this.activateObjectFail = activateObjectFail;
+        }
+
+        public boolean isPassivateObjectFail() {
+            return passivateObjectFail;
+        }
+
+        public void setPassivateObjectFail(boolean passivateObjectFail) {
+            this.passivateObjectFail = passivateObjectFail;
+        }
+
+        public Object makeObject(final Object key) throws Exception {
+            final MethodCall call = new MethodCall("makeObject", key);
+            methodCalls.add(call);
+            int count = this.count++;
+            if (makeObjectFail) {
+                throw new PrivateException("makeObject");
+            }
+            final Integer obj = new Integer(count);
+            call.setReturned(obj);
+            return obj;
+        }
+
+        public void activateObject(final Object key, final Object obj) throws Exception {
+            methodCalls.add(new MethodCall("activateObject", key, obj));
+            if (activateObjectFail) {
+                throw new PrivateException("activateObject");
+            }
+        }
+
+        public boolean validateObject(final Object key, final Object obj) {
+            final MethodCall call = new MethodCall("validateObject", key, obj);
+            methodCalls.add(call);
+            if (validateObjectFail) {
+                throw new PrivateException("validateObject");
+            }
+            final boolean r = true;
+            call.returned(Boolean.valueOf(r));
+            return r;
+        }
+
+        public void passivateObject(final Object key, final Object obj) throws Exception {
+            methodCalls.add(new MethodCall("passivateObject", key, obj));
+            if (passivateObjectFail) {
+                throw new PrivateException("passivateObject");
+            }
+        }
+
+        public void destroyObject(final Object key, final Object obj) throws Exception {
+            methodCalls.add(new MethodCall("destroyObject", key, obj));
+            if (destroyObjectFail) {
+                throw new PrivateException("destroyObject");
+            }
+        }
+    }
 }

Modified: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestObjectPool.java Wed Mar 15 14:28:20 2006
@@ -18,7 +18,6 @@
 import junit.framework.TestCase;
 
 import java.util.List;
-import java.util.Collections;
 import java.util.ArrayList;
 import java.util.Iterator;
 
@@ -467,7 +466,7 @@
         pool.close();
     }
 
-    private void removeDestroyObjectCall(List calls) {
+    static void removeDestroyObjectCall(List calls) {
         Iterator iter = calls.iterator();
         while (iter.hasNext()) {
             MethodCall call = (MethodCall)iter.next();
@@ -603,97 +602,6 @@
             if (destroyObjectFail) {
                 throw new PrivateException("destroyObject");
             }
-        }
-    }
-
-    private static class MethodCall {
-        private final String name;
-        private final List params;
-        private Object returned;
-
-        MethodCall(final String name) {
-            this(name, null);
-        }
-
-        MethodCall(final String name, final Object param) {
-            this(name, Collections.singletonList(param));
-        }
-
-        MethodCall(final String name, final List params) {
-            if (name == null) {
-                throw new IllegalArgumentException("name must not be null.");
-            }
-            this.name = name;
-            if (params != null) {
-                this.params = params;
-            } else {
-                this.params = Collections.EMPTY_LIST;
-            }
-        }
-
-        public String getName() {
-            return name;
-        }
-
-        public List getParams() {
-            return params;
-        }
-
-        public Object getReturned() {
-            return returned;
-        }
-
-        public void setReturned(final Object returned) {
-            this.returned = returned;
-        }
-
-        public MethodCall returned(Object obj) {
-            setReturned(obj);
-            return this;
-        }
-
-        public boolean equals(final Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-
-            final MethodCall that = (MethodCall)o;
-
-            if (name != null ? !name.equals(that.name) : that.name != null) return false;
-            if (params != null ? !params.equals(that.params) : that.params != null) return false;
-            if (returned != null ? !returned.equals(that.returned) : that.returned != null) return false;
-
-            return true;
-        }
-
-        public int hashCode() {
-            int result;
-            result = (name != null ? name.hashCode() : 0);
-            result = 29 * result + (params != null ? params.hashCode() : 0);
-            result = 29 * result + (returned != null ? returned.hashCode() : 0);
-            return result;
-        }
-
-        public String toString() {
-            final StringBuffer sb = new StringBuffer();
-            sb.append("MethodCall");
-            sb.append("{name='").append(name).append('\'');
-            if (!params.isEmpty()) {
-                sb.append(", params=").append(params);
-            }
-            if (returned != null) {
-                sb.append(", returned=").append(returned);
-            }
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-    /**
-     * An exception that only is thrown by this test.
-     */
-    private static class PrivateException extends RuntimeException {
-        PrivateException(final String message) {
-            super(message);
         }
     }
 }

Modified: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java?rev=386186&r1=386185&r2=386186&view=diff
==============================================================================
--- jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java (original)
+++ jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/impl/TestGenericKeyedObjectPool.java Wed Mar 15 14:28:20 2006
@@ -63,6 +63,10 @@
         return pool;
     }
 
+    protected KeyedObjectPool makeEmptyPool(KeyedPoolableObjectFactory factory) {
+        return new GenericKeyedObjectPool(factory);
+    }
+
     protected Object getNthObject(Object key, int n) {
         return String.valueOf(key) + String.valueOf(n);
     }
@@ -82,17 +86,6 @@
         super.tearDown();
         pool.close();
         pool = null;
-    }
-
-    public void testWithInitiallyInvalid() throws Exception {
-        GenericKeyedObjectPool pool = new GenericKeyedObjectPool(new SimpleFactory(false));
-        pool.setTestOnBorrow(true);
-        try {
-            pool.borrowObject("xyzzy");
-            fail("Expected NoSuchElementException");
-        } catch(NoSuchElementException e) {
-            // expected
-        }
     }
 
     public void testNegativeMaxActive() throws Exception {



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org