Author: psteitz Date: Mon Jun 21 17:54:03 2010 New Revision: 956656 URL: http://svn.apache.org/viewvc?rev=956656&view=rev Log: Javadoc.
Modified: commons/proper/pool/trunk/src/java/org/apache/commons/pool/PoolUtils.java Modified: commons/proper/pool/trunk/src/java/org/apache/commons/pool/PoolUtils.java URL: http://svn.apache.org/viewvc/commons/proper/pool/trunk/src/java/org/apache/commons/pool/PoolUtils.java?rev=956656&r1=956655&r2=956656&view=diff ============================================================================== --- commons/proper/pool/trunk/src/java/org/apache/commons/pool/PoolUtils.java (original) +++ commons/proper/pool/trunk/src/java/org/apache/commons/pool/PoolUtils.java Mon Jun 21 17:54:03 2010 @@ -1399,11 +1399,30 @@ public final class PoolUtils { } } + /** + * Timer task that adds objects to the pool until the number of idle + * instances for the given key reaches the configured minIdle. Note that this is not the + * same as the pool's minIdle setting. + * + */ private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask { + /** Minimum number of idle instances. Not the same as pool.getMinIdle(). */ private final int minIdle; + + /** Key to ensure minIdle for */ private final Object key; + + /** Keyed object pool */ private final KeyedObjectPool keyedPool; + /** + * Create a new KeyedObjecPoolMinIdleTimerTask. + * + * @param keyedPool keyed object pool + * @param key key to ensure minimum number of idle instances + * @param minIdle minimum number of idle instances + * @throws IllegalArgumentException if the key is null + */ KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, final Object key, final int minIdle) throws IllegalArgumentException { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); @@ -1413,6 +1432,9 @@ public final class PoolUtils { this.minIdle = minIdle; } + /** + * {...@inheritdoc} + */ public void run() { boolean success = false; try { @@ -1432,6 +1454,9 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("KeyedObjectPoolMinIdleTimerTask"); @@ -1443,10 +1468,30 @@ public final class PoolUtils { } } + /** + * A synchronized (thread-safe) ObjectPool backed by the specified ObjectPool. + * + * <p><b>Note:</b> + * This should not be used on pool implementations that already provide proper synchronization + * such as the pools provided in the Commons Pool library. Wrapping a pool that + * {...@link #wait() waits} for poolable objects to be returned before allowing another one to be + * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. + * </p> + */ private static class SynchronizedObjectPool implements ObjectPool { + + /** Object whose monitor is used to synchronize methods on the wrapped pool. */ private final Object lock; + + /** the underlying object pool */ private final ObjectPool pool; + /** + * Create a new SynchronizedObjectPool wrapping the given pool. + * + * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. + * @throws IllegalArgumentException if the pool is null + */ SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); @@ -1455,12 +1500,18 @@ public final class PoolUtils { lock = new Object(); } + /** + * {...@inheritdoc} + */ public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { synchronized (lock) { return pool.borrowObject(); } } + /** + * {...@inheritdoc} + */ public void returnObject(final Object obj) { synchronized (lock) { try { @@ -1471,6 +1522,9 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void invalidateObject(final Object obj) { synchronized (lock) { try { @@ -1481,30 +1535,45 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { synchronized (lock) { pool.addObject(); } } + /** + * {...@inheritdoc} + */ public int getNumIdle() throws UnsupportedOperationException { synchronized (lock) { return pool.getNumIdle(); } } + /** + * {...@inheritdoc} + */ public int getNumActive() throws UnsupportedOperationException { synchronized (lock) { return pool.getNumActive(); } } + /** + * {...@inheritdoc} + */ public void clear() throws Exception, UnsupportedOperationException { synchronized (lock) { pool.clear(); } } + /** + * {...@inheritdoc} + */ public void close() { try { synchronized (lock) { @@ -1515,12 +1584,21 @@ public final class PoolUtils { } } + /** + * Sets the factory used by the pool. + * + * @param factory new PoolableObjectFactory + * @deprecated to be removed in pool 2.0 + */ public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { synchronized (lock) { pool.setFactory(factory); } } + /** + * {...@inheritdoc} + */ public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedObjectPool"); @@ -1530,10 +1608,30 @@ public final class PoolUtils { } } + /** + * A synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. + * + * <p><b>Note:</b> + * This should not be used on pool implementations that already provide proper synchronization + * such as the pools provided in the Commons Pool library. Wrapping a pool that + * {...@link #wait() waits} for poolable objects to be returned before allowing another one to be + * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. + * </p> + */ private static class SynchronizedKeyedObjectPool implements KeyedObjectPool { + + /** Object whose monitor is used to synchronize methods on the wrapped pool. */ private final Object lock; + + /** Underlying object pool */ private final KeyedObjectPool keyedPool; + /** + * Create a new SynchronizedKeyedObjectPool wrapping the given pool + * + * @param keyedPool KeyedObjectPool to wrap + * @throws IllegalArgumentException if keyedPool is null + */ SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); @@ -1542,12 +1640,18 @@ public final class PoolUtils { lock = new Object(); } + /** + * {...@inheritdoc} + */ public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { synchronized (lock) { return keyedPool.borrowObject(key); } } + /** + * {...@inheritdoc} + */ public void returnObject(final Object key, final Object obj) { synchronized (lock) { try { @@ -1558,6 +1662,9 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void invalidateObject(final Object key, final Object obj) { synchronized (lock) { try { @@ -1568,48 +1675,72 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { synchronized (lock) { keyedPool.addObject(key); } } + /** + * {...@inheritdoc} + */ public int getNumIdle(final Object key) throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumIdle(key); } } + /** + * {...@inheritdoc} + */ public int getNumActive(final Object key) throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumActive(key); } } + /** + * {...@inheritdoc} + */ public int getNumIdle() throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumIdle(); } } + /** + * {...@inheritdoc} + */ public int getNumActive() throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumActive(); } } + /** + * {...@inheritdoc} + */ public void clear() throws Exception, UnsupportedOperationException { synchronized (lock) { keyedPool.clear(); } } + /** + * {...@inheritdoc} + */ public void clear(final Object key) throws Exception, UnsupportedOperationException { synchronized (lock) { keyedPool.clear(key); } } + /** + * {...@inheritdoc} + */ public void close() { try { synchronized (lock) { @@ -1620,12 +1751,21 @@ public final class PoolUtils { } } + /** + * Sets the object factory used by the pool. + * + * @param factory KeyedPoolableObjectFactory used by the pool + * @deprecated to be removed in pool 2.0 + */ public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { synchronized (lock) { keyedPool.setFactory(factory); } } + /** + * {...@inheritdoc} + */ public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedKeyedObjectPool"); @@ -1635,10 +1775,27 @@ public final class PoolUtils { } } + /** + * A fully synchronized PoolableObjectFactory that wraps a PoolableObjectFactory and synchronizes + * access to the wrapped factory methods. + * + * <p><b>Note:</b> + * This should not be used on pool implementations that already provide proper synchronization + * such as the pools provided in the Commons Pool library. </p> + */ private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory { + /** Synchronization lock */ private final Object lock; + + /** Wrapped factory */ private final PoolableObjectFactory factory; + /** + * Create a SynchronizedPoolableObjectFactory wrapping the given factory. + * + * @param factory underlying factory to wrap + * @throws IllegalArgumentException if the factory is null + */ SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException { if (factory == null) { throw new IllegalArgumentException("factory must not be null."); @@ -1647,36 +1804,54 @@ public final class PoolUtils { lock = new Object(); } + /** + * {...@inheritdoc} + */ public Object makeObject() throws Exception { synchronized (lock) { return factory.makeObject(); } } + /** + * {...@inheritdoc} + */ public void destroyObject(final Object obj) throws Exception { synchronized (lock) { factory.destroyObject(obj); } } + /** + * {...@inheritdoc} + */ public boolean validateObject(final Object obj) { synchronized (lock) { return factory.validateObject(obj); } } + /** + * {...@inheritdoc} + */ public void activateObject(final Object obj) throws Exception { synchronized (lock) { factory.activateObject(obj); } } + /** + * {...@inheritdoc} + */ public void passivateObject(final Object obj) throws Exception { synchronized (lock) { factory.passivateObject(obj); } } + /** + * {...@inheritdoc} + */ public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedPoolableObjectFactory"); @@ -1686,10 +1861,27 @@ public final class PoolUtils { } } + /** + * A fully synchronized KeyedPoolableObjectFactory that wraps a KeyedPoolableObjectFactory and synchronizes + * access to the wrapped factory methods. + * + * <p><b>Note:</b> + * This should not be used on pool implementations that already provide proper synchronization + * such as the pools provided in the Commons Pool library. </p> + */ private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory { + /** Synchronization lock */ private final Object lock; + + /** Wrapped factory */ private final KeyedPoolableObjectFactory keyedFactory; + /** + * Create a SynchronizedKeyedPoolableObjectFactory wrapping the given factory. + * + * @param keyedFactory underlying factory to wrap + * @throws IllegalArgumentException if the factory is null + */ SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException { if (keyedFactory == null) { throw new IllegalArgumentException("keyedFactory must not be null."); @@ -1698,36 +1890,54 @@ public final class PoolUtils { lock = new Object(); } + /** + * {...@inheritdoc} + */ public Object makeObject(final Object key) throws Exception { synchronized (lock) { return keyedFactory.makeObject(key); } } + /** + * {...@inheritdoc} + */ public void destroyObject(final Object key, final Object obj) throws Exception { synchronized (lock) { keyedFactory.destroyObject(key, obj); } } + /** + * {...@inheritdoc} + */ public boolean validateObject(final Object key, final Object obj) { synchronized (lock) { return keyedFactory.validateObject(key, obj); } } + /** + * {...@inheritdoc} + */ public void activateObject(final Object key, final Object obj) throws Exception { synchronized (lock) { keyedFactory.activateObject(key, obj); } } + /** + * {...@inheritdoc} + */ public void passivateObject(final Object key, final Object obj) throws Exception { synchronized (lock) { keyedFactory.passivateObject(key, obj); } } + /** + * {...@inheritdoc} + */ public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedKeyedPoolableObjectFactory"); @@ -1739,22 +1949,49 @@ public final class PoolUtils { /** * Encapsulate the logic for when the next poolable object should be discarded. + * Each time update is called, the next time to shrink is recomputed, based on + * the float factor, number of idle instances in the pool and high water mark. + * Float factor is assumed to be between 0 and 1. Values closer to 1 cause + * less frequent erosion events. Erosion event timing also depends on numIdle. + * When this value is relatively high (close to previously established high water + * mark), erosion occurs more frequently. */ private static class ErodingFactor { + /** Determines frequency of "erosion" events */ private final float factor; + + /** Time of next shrink event */ private transient volatile long nextShrink; + + /** High water mark - largest numIdle encountered */ private transient volatile int idleHighWaterMark; + /** + * Create a new ErodingFactor with the given erosion factor. + * + * @param factor erosion factor + */ public ErodingFactor(final float factor) { this.factor = factor; nextShrink = System.currentTimeMillis() + (long)(900000 * factor); // now + 15 min * factor idleHighWaterMark = 1; } + /** + * Updates internal state based on numIdle and the current time. + * + * @param numIdle number of idle elements in the pool + */ public void update(final int numIdle) { update(System.currentTimeMillis(), numIdle); } + /** + * Updates internal state using the supplied time and numIdle. + * + * @param now current time + * @param numIdle number of idle elements in the pool + */ public void update(final long now, final int numIdle) { final int idle = Math.max(0, numIdle); idleHighWaterMark = Math.max(idle, idleHighWaterMark); @@ -1763,10 +2000,18 @@ public final class PoolUtils { nextShrink = now + (long)(minutes * 60000f * factor); } + /** + * Returns the time of the next erosion event. + * + * @return next shrink time + */ public long getNextShrink() { return nextShrink; } + /** + * {...@inheritdoc} + */ public String toString() { return "ErodingFactor{" + "factor=" + factor + @@ -1775,19 +2020,47 @@ public final class PoolUtils { } } + /** + * Decorates an object pool, adding "eroding" behavior. Based on the + * configured {...@link #factor erosion factor}, objects returning to the pool + * may be invalidated instead of being added to idle capacity. + * + */ private static class ErodingObjectPool implements ObjectPool { + /** Underlying object pool */ private final ObjectPool pool; + + /** Erosion factor */ private final ErodingFactor factor; + /** + * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. + * + * @param pool underlying pool + * @param factor erosion factor - determines the frequency of erosion events + * @see #factor + */ public ErodingObjectPool(final ObjectPool pool, final float factor) { this.pool = pool; this.factor = new ErodingFactor(factor); } + /** + * {...@inheritdoc} + */ public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { return pool.borrowObject(); } + /** + * Returns obj to the pool, unless erosion is triggered, in which + * case obj is invalidated. Erosion is triggered when there are idle instances in + * the pool and more than the {...@link #factor erosion factor}-determined time has elapsed + * since the last returnObject activation. + * + * @param obj object to return or invalidate + * @see #factor + */ public void returnObject(final Object obj) { boolean discard = false; final long now = System.currentTimeMillis(); @@ -1812,6 +2085,9 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void invalidateObject(final Object obj) { try { pool.invalidateObject(obj); @@ -1820,22 +2096,37 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { pool.addObject(); } + /** + * {...@inheritdoc} + */ public int getNumIdle() throws UnsupportedOperationException { return pool.getNumIdle(); } + /** + * {...@inheritdoc} + */ public int getNumActive() throws UnsupportedOperationException { return pool.getNumActive(); } + /** + * {...@inheritdoc} + */ public void clear() throws Exception, UnsupportedOperationException { pool.clear(); } + /** + * {...@inheritdoc} + */ public void close() { try { pool.close(); @@ -1844,10 +2135,17 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + * @deprecated to be removed in pool 2.0 + */ public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { pool.setFactory(factory); } + /** + * {...@inheritdoc} + */ public String toString() { return "ErodingObjectPool{" + "factor=" + factor + @@ -1856,14 +2154,37 @@ public final class PoolUtils { } } + /** + * Decorates a keyed object pool, adding "eroding" behavior. Based on the + * configured {...@link #factor erosion factor}, objects returning to the pool + * may be invalidated instead of being added to idle capacity. + * + */ private static class ErodingKeyedObjectPool implements KeyedObjectPool { + /** Underlying pool */ private final KeyedObjectPool keyedPool; + + /** Erosion factor */ private final ErodingFactor erodingFactor; + /** + * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. + * + * @param keyedPool underlying pool + * @param factor erosion factor - determines the frequency of erosion events + * @see #factor + */ public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) { this(keyedPool, new ErodingFactor(factor)); } + /** + * Create an ErodingObjectPool wrapping the given pool using the specified erosion factor. + * + * @param keyedPool underlying pool - must not be null + * @param erodingFactor erosion factor - determines the frequency of erosion events + * @see #factor + */ protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final ErodingFactor erodingFactor) { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); @@ -1872,10 +2193,23 @@ public final class PoolUtils { this.erodingFactor = erodingFactor; } + /** + * {...@inheritdoc} + */ public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { return keyedPool.borrowObject(key); } + /** + * Returns obj to the pool, unless erosion is triggered, in which + * case obj is invalidated. Erosion is triggered when there are idle instances in + * the pool associated with the given key and more than the configured {...@link #factor erosion factor} + * time has elapsed since the last returnObject activation. + * + * @param obj object to return or invalidate + * @param key key + * @see #factor + */ public void returnObject(final Object key, final Object obj) throws Exception { boolean discard = false; final long now = System.currentTimeMillis(); @@ -1901,14 +2235,25 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ protected int numIdle(final Object key) { return getKeyedPool().getNumIdle(); } + /** + * Returns the eroding factor for the given key + * @param key key + * @return eroding factor for the given keyed pool + */ protected ErodingFactor getErodingFactor(final Object key) { return erodingFactor; } + /** + * {...@inheritdoc} + */ public void invalidateObject(final Object key, final Object obj) { try { keyedPool.invalidateObject(key, obj); @@ -1917,34 +2262,58 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + */ public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { keyedPool.addObject(key); } + /** + * {...@inheritdoc} + */ public int getNumIdle() throws UnsupportedOperationException { return keyedPool.getNumIdle(); } + /** + * {...@inheritdoc} + */ public int getNumIdle(final Object key) throws UnsupportedOperationException { return keyedPool.getNumIdle(key); } + /** + * {...@inheritdoc} + */ public int getNumActive() throws UnsupportedOperationException { return keyedPool.getNumActive(); } + /** + * {...@inheritdoc} + */ public int getNumActive(final Object key) throws UnsupportedOperationException { return keyedPool.getNumActive(key); } + /** + * {...@inheritdoc} + */ public void clear() throws Exception, UnsupportedOperationException { keyedPool.clear(); } + /** + * {...@inheritdoc} + */ public void clear(final Object key) throws Exception, UnsupportedOperationException { keyedPool.clear(key); } + /** + * {...@inheritdoc} + */ public void close() { try { keyedPool.close(); @@ -1953,14 +2322,26 @@ public final class PoolUtils { } } + /** + * {...@inheritdoc} + * @deprecated to be removed in pool 2.0 + */ public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { keyedPool.setFactory(factory); } + /** + * Returns the underlying pool + * + * @return the keyed pool that this ErodingKeyedObjectPool wraps + */ protected KeyedObjectPool getKeyedPool() { return keyedPool; } + /** + * {...@inheritdoc} + */ public String toString() { return "ErodingKeyedObjectPool{" + "erodingFactor=" + erodingFactor + @@ -1969,19 +2350,38 @@ public final class PoolUtils { } } + /** + * Extends ErodingKeyedObjectPool to allow erosion to take place on a per-key + * basis. Timing of erosion events is tracked separately for separate keyed pools. + */ private static class ErodingPerKeyKeyedObjectPool extends ErodingKeyedObjectPool { + /** Erosion factor - same for all pools */ private final float factor; + + /** Map of ErodingFactor instances keyed on pool keys */ private final Map factors = Collections.synchronizedMap(new HashMap()); + /** + * Create a new ErordingPerKeyKeyedObjectPool decorating the given keyed pool with + * the specified erosion factor. + * @param keyedPool underlying keyed pool + * @param factor erosion factor + */ public ErodingPerKeyKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) { super(keyedPool, null); this.factor = factor; } + /** + * {...@inheritdoc} + */ protected int numIdle(final Object key) { return getKeyedPool().getNumIdle(key); } + /** + * {...@inheritdoc} + */ protected ErodingFactor getErodingFactor(final Object key) { ErodingFactor factor = (ErodingFactor)factors.get(key); // this may result in two ErodingFactors being created for a key @@ -1993,6 +2393,9 @@ public final class PoolUtils { return factor; } + /** + * {...@inheritdoc} + */ public String toString() { return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor +