Wouldn't this class be better named, PoolUtils?
-----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] Sent: Saturday, March 04, 2006 12:42 AM To: [EMAIL PROTECTED] Subject: svn commit: r383042 - in /jakarta/commons/proper/pool/trunk/src: java/org/apache/commons/pool/Pools.java test/org/apache/commons/pool/TestPools.java Author: sandymac Date: Fri Mar 3 21:42:18 2006 New Revision: 383042 URL: http://svn.apache.org/viewcvs?rev=383042&view=rev Log: A collection of utility methods for pool, à la java.util.Collections. Added: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/Pools.jav a jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestPools .java Added: jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/Pools.jav a URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/java/org /apache/commons/pool/Pools.java?rev=383042&view=auto ============================================================================ == --- jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/Pools.jav a (added) +++ jakarta/commons/proper/pool/trunk/src/java/org/apache/commons/pool/Pools.jav a Fri Mar 3 21:42:18 2006 @@ -0,0 +1,885 @@ +/* + * 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.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Timer; +import java.util.TimerTask; + +/** + * This class consists exclusively of static methods that operate on or return pool related interfaces. + * + * @author Sandy McArthur + * @version $Revision$ $Date$ + */ +public final class Pools { + + /** + * Timer used to periodically check pools idle object count. + * Because a [EMAIL PROTECTED] Timer} creates a [EMAIL PROTECTED] Thread} this is lazily instantiated. + */ + private static Timer MIN_IDLE_TIMER; + + /** + * Prevent instantiation. + */ + private Pools() { + } + + /** + * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is + * needed. This method is the equivalent of calling + * [EMAIL PROTECTED] #adapt(KeyedPoolableObjectFactory, Object) Pools.adapt(aKeyedPoolableObjectFactory, new Object())}. + * + * @param keyedFactory the [EMAIL PROTECTED] KeyedPoolableObjectFactory} to delegate to. + * @return a [EMAIL PROTECTED] PoolableObjectFactory} that delegates to <code>keyedFactory</code> with an internal key. + * @throws IllegalArgumentException when <code>keyedFactory</code> is <code>null</code>. + * @see #adapt(KeyedPoolableObjectFactory, Object) + */ + public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException { + return adapt(keyedFactory, new Object()); + } + + /** + * Adapt a <code>KeyedPoolableObjectFactory</code> instance to work where a <code>PoolableObjectFactory</code> is + * needed using the specified <code>key</code> when delegating. + * + * @param keyedFactory the [EMAIL PROTECTED] KeyedPoolableObjectFactory} to delegate to. + * @param key the key to use when delegating. + * @return a [EMAIL PROTECTED] PoolableObjectFactory} that delegates to <code>keyedFactory</code> with the specified key. + * @throws IllegalArgumentException when <code>keyedFactory</code> or <code>key</code> is <code>null</code>. + * @see #adapt(KeyedPoolableObjectFactory) + */ + public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException { + return new PoolableObjectFactoryAdaptor(keyedFactory, key); + } + + /** + * Adapt a <code>PoolableObjectFactory</code> instance to work where a <code>KeyedPoolableObjectFactory</code> is + * needed. The key is ignored. + * + * @param factory the [EMAIL PROTECTED] PoolableObjectFactory} to delegate to. + * @return a [EMAIL PROTECTED] KeyedPoolableObjectFactory} that delegates to <code>factory</code> ignoring the key. + * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>. + */ + public static KeyedPoolableObjectFactory adapt(final PoolableObjectFactory factory) throws IllegalArgumentException { + return new KeyedPoolableObjectFactoryAdaptor(factory); + } + + /** + * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed. This is the + * equivalent of calling [EMAIL PROTECTED] #adapt(KeyedObjectPool, Object) Pools.adapt(aKeyedObjectPool, new Object())}. + * + * @param keyedPool the [EMAIL PROTECTED] KeyedObjectPool} to delegate to. + * @return an [EMAIL PROTECTED] ObjectPool} that delegates to <code>keyedPool</code> with an internal key. + * @throws IllegalArgumentException when <code>keyedPool</code> is <code>null</code>. + * @see #adapt(KeyedObjectPool, Object) + */ + public static ObjectPool adapt(final KeyedObjectPool keyedPool) throws IllegalArgumentException { + return adapt(keyedPool, new Object()); + } + + /** + * Adapt a <code>KeyedObjectPool</code> instance to work where an <code>ObjectPool</code> is needed using the + * specified <code>key</code> when delegating. + * + * @param keyedPool the [EMAIL PROTECTED] KeyedObjectPool} to delegate to. + * @param key the key to use when delegating. + * @return an [EMAIL PROTECTED] ObjectPool} that delegates to <code>keyedPool</code> with the specified key. + * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>. + * @see #adapt(KeyedObjectPool) + */ + public static ObjectPool adapt(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException { + return new ObjectPoolAdaptor(keyedPool, key); + } + + /** + * Adapt an <code>ObjectPool</code> to work where an <code>KeyedObjectPool</code> is needed. + * The key is ignored. + * + * @param pool the [EMAIL PROTECTED] ObjectPool} to delegate to. + * @return a [EMAIL PROTECTED] KeyedObjectPool} that delegates to <code>pool</code> ignoring the key. + * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>. + */ + public static KeyedObjectPool adapt(final ObjectPool pool) throws IllegalArgumentException { + return new KeyedObjectPoolAdaptor(pool); + } + + /** + * Periodically check the idle object count for the pool. At most one idle object will be added per period. + * If there is an exception when calling [EMAIL PROTECTED] ObjectPool#addObject()} then no more checks will be performed. + * + * @param pool the pool to check periodically. + * @param minIdle if the [EMAIL PROTECTED] ObjectPool#getNumIdle()} is less than this then add an idle object. + * @param period the frequency to check the number of idle objects in a pool, see + * [EMAIL PROTECTED] Timer#schedule(TimerTask, long, long)}. + * @return the [EMAIL PROTECTED] TimerTask} that will periodically check the pools idle object count. + * @throws IllegalArgumentException when <code>pool</code> is <code>null</code> or + * when <code>minIdle</code> is negative or when <code>period</code> isn't + * valid for [EMAIL PROTECTED] Timer#schedule(TimerTask, long, long)}. + */ + public static TimerTask checkMinIdle(final ObjectPool pool, final int minIdle, final long period) throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + if (minIdle < 0) { + throw new IllegalArgumentException("minIdle must be non-negative."); + } + final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle); + getMinIdleTimer().schedule(task, 0L, period); + return task; + } + + /** + * Periodically check the idle object count for the key in the pool. At most one idle object will be added per period. + * If there is an exception when calling [EMAIL PROTECTED] KeyedObjectPool#addObject(Object)} then no more checks for that key + * will be performed. + * + * @param keyedPool the pool to check periodically. + * @param key the key to check the idle count of. + * @param minIdle if the [EMAIL PROTECTED] KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object. + * @param period the frequency to check the number of idle objects in a pool, see + * [EMAIL PROTECTED] Timer#schedule(TimerTask, long, long)}. + * @return the [EMAIL PROTECTED] TimerTask} that will periodically check the pools idle object count. + * @throws IllegalArgumentException when <code>keyedPool</code>, <code>key</code> is <code>null</code> or + * when <code>minIdle</code> is negative or when <code>period</code> isn't + * valid for [EMAIL PROTECTED] Timer#schedule(TimerTask, long, long)}. + */ + public static TimerTask checkMinIdle(final KeyedObjectPool keyedPool, final Object key, final int minIdle, final long period) throws IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (key == null) { + throw new IllegalArgumentException("key must not be null."); + } + if (minIdle < 0) { + throw new IllegalArgumentException("minIdle must be non-negative."); + } + final TimerTask task = new KeyedObjectPoolMinIdleTimerTask(keyedPool, key, minIdle); + getMinIdleTimer().schedule(task, 0L, period); + return task; + } + + /** + * Periodically check the idle object count for each key in the <code>Collection</code> <code>keys</code> in the pool. + * At most one idle object will be added per period. + * + * @param keyedPool the pool to check periodically. + * @param keys a collection of keys to check the idle object count. + * @param minIdle if the [EMAIL PROTECTED] KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object. + * @param period the frequency to check the number of idle objects in a pool, see + * [EMAIL PROTECTED] Timer#schedule(TimerTask, long, long)}. + * @return a [EMAIL PROTECTED] Map} of key and [EMAIL PROTECTED] TimerTask} pairs that will periodically check the pools idle object count. + * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or any of the values in the + * collection is <code>null</code> or when <code>minIdle</code> is negative or when <code>period</code> isn't + * valid for [EMAIL PROTECTED] Timer#schedule(TimerTask, long, long)}. + * @see #checkMinIdle(KeyedObjectPool, Object, int, long) + */ + public static Map checkMinIdle(final KeyedObjectPool keyedPool, final Collection keys, final int minIdle, final long period) throws IllegalArgumentException { + if (keys == null) { + throw new IllegalArgumentException("keys must not be null."); + } + final Map tasks = new HashMap(keys.size()); + final Iterator iter = keys.iterator(); + while (iter.hasNext()) { + final Object key = iter.next(); + final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period); + tasks.put(key, task); + } + return tasks; + } + + /** + * Call <code>addObject()</code> on <code>pool</code> <code>count</code> number of times. + * + * @param pool the pool to prefill. + * @param count the number of idle objects to add. + * @throws Exception when [EMAIL PROTECTED] ObjectPool#addObject()} fails. + * @throws IllegalArgumentException when <code>pool</code> is <code>null</code>. + */ + public static void prefill(final ObjectPool pool, final int count) throws Exception, IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + for (int i = 0; i < count; i++) { + pool.addObject(); + } + } + + /** + * Call <code>addObject(Object)</code> on <code>keyedPool</code> with <code>key</code> <code>count</code> + * number of times. + * + * @param keyedPool the pool to prefill. + * @param key the key to add objects for. + * @param count the number of idle objects to add for <code>key</code>. + * @throws Exception when [EMAIL PROTECTED] KeyedObjectPool#addObject(Object)} fails. + * @throws IllegalArgumentException when <code>keyedPool</code> or <code>key</code> is <code>null</code>. + */ + public static void prefill(final KeyedObjectPool keyedPool, final Object key, final int count) throws Exception, IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (key == null) { + throw new IllegalArgumentException("key must not be null."); + } + for (int i = 0; i < count; i++) { + keyedPool.addObject(key); + } + } + + /** + * Call <code>addObject(Object)</code> on <code>keyedPool</code> with each key in <code>keys</code> for + * <code>count</code> number of times. This has the same effect as calling + * [EMAIL PROTECTED] #prefill(KeyedObjectPool, Object, int)} for each key in the <code>keys</code> collection. + * + * @param keyedPool the pool to prefill. + * @param keys [EMAIL PROTECTED] Collection} of keys to add objects for. + * @param count the number of idle objects to add for each <code>key</code>. + * @throws Exception when [EMAIL PROTECTED] KeyedObjectPool#addObject(Object)} fails. + * @throws IllegalArgumentException when <code>keyedPool</code>, <code>keys</code>, or + * any value in <code>keys</code> is <code>null</code>. + * @see #prefill(KeyedObjectPool, Object, int) + */ + public static void prefill(final KeyedObjectPool keyedPool, final Collection keys, final int count) throws Exception, IllegalArgumentException { + if (keys == null) { + throw new IllegalArgumentException("keys must not be null."); + } + final Iterator iter = keys.iterator(); + while (iter.hasNext()) { + prefill(keyedPool, iter.next(), count); + } + } + + /** + * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool. + * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. + * @return a synchronized view of the specified ObjectPool. + */ + public static ObjectPool synchronizedPool(final ObjectPool pool) { + return new SynchronizedObjectPool(pool); + } + + /** + * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. + * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool. + * @return a synchronized view of the specified KeyedObjectPool. + */ + public static KeyedObjectPool synchronizedPool(final KeyedObjectPool keyedPool) { + return new SynchronizedKeyedObjectPool(keyedPool); + } + + /** + * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory. + * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory. + * @return a synchronized view of the specified PoolableObjectFactory. + */ + public static PoolableObjectFactory synchronizedPoolableFactory(final PoolableObjectFactory factory) { + return new SynchronizedPoolableObjectFactory(factory); + } + + /** + * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory. + * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory. + * @return a synchronized view of the specified KeyedPoolableObjectFactory. + */ + public static KeyedPoolableObjectFactory synchronizedPoolableFactory(final KeyedPoolableObjectFactory keyedFactory) { + return new SynchronizedKeyedPoolableObjectFactory(keyedFactory); + } + + /** + * Get the <code>Timer</code> for checking pool's idle count. Lazily create the [EMAIL PROTECTED] Timer} as needed. + * @return the [EMAIL PROTECTED] Timer} for checking pool's idle count. + */ + private static synchronized Timer getMinIdleTimer() { + if (MIN_IDLE_TIMER == null) { + MIN_IDLE_TIMER = new Timer(true); + } + return MIN_IDLE_TIMER; + } + + private static class PoolableObjectFactoryAdaptor implements PoolableObjectFactory { + private final Object key; + private final KeyedPoolableObjectFactory keyedFactory; + + PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException { + if (keyedFactory == null) { + throw new IllegalArgumentException("keyedFactory must not be null."); + } + if (key == null) { + throw new IllegalArgumentException("key must not be null."); + } + this.keyedFactory = keyedFactory; + this.key = key; + } + + public Object makeObject() throws Exception { + return keyedFactory.makeObject(key); + } + + public void destroyObject(final Object obj) throws Exception { + keyedFactory.destroyObject(key, obj); + } + + public boolean validateObject(final Object obj) { + return keyedFactory.validateObject(key, obj); + } + + public void activateObject(final Object obj) throws Exception { + keyedFactory.activateObject(key, obj); + } + + public void passivateObject(final Object obj) throws Exception { + keyedFactory.passivateObject(key, obj); + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("PoolableObjectFactoryAdaptor"); + sb.append("{key=").append(key); + sb.append(", keyedFactory=").append(keyedFactory); + sb.append('}'); + return sb.toString(); + } + } + + private static class KeyedPoolableObjectFactoryAdaptor implements KeyedPoolableObjectFactory { + private final PoolableObjectFactory factory; + + KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory factory) throws IllegalArgumentException { + if (factory == null) { + throw new IllegalArgumentException("factory must not be null."); + } + this.factory = factory; + } + + public Object makeObject(final Object key) throws Exception { + return factory.makeObject(); + } + + public void destroyObject(final Object key, final Object obj) throws Exception { + factory.destroyObject(obj); + } + + public boolean validateObject(final Object key, final Object obj) { + return factory.validateObject(obj); + } + + public void activateObject(final Object key, final Object obj) throws Exception { + factory.activateObject(obj); + } + + public void passivateObject(final Object key, final Object obj) throws Exception { + factory.passivateObject(obj); + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("KeyedPoolableObjectFactoryAdaptor"); + sb.append("{factory=").append(factory); + sb.append('}'); + return sb.toString(); + } + } + + private static class ObjectPoolAdaptor implements ObjectPool { + private final Object key; + private final KeyedObjectPool keyedPool; + + ObjectPoolAdaptor(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + if (key == null) { + throw new IllegalArgumentException("key must not be null."); + } + this.keyedPool = keyedPool; + this.key = key; + } + + public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { + return keyedPool.borrowObject(key); + } + + public void returnObject(final Object obj) throws Exception { + keyedPool.returnObject(key, obj); + } + + public void invalidateObject(final Object obj) throws Exception { + keyedPool.invalidateObject(key, obj); + } + + public void addObject() throws Exception, IllegalStateException { + keyedPool.addObject(key); + } + + public int getNumIdle() throws UnsupportedOperationException { + return keyedPool.getNumIdle(key); + } + + public int getNumActive() throws UnsupportedOperationException { + return keyedPool.getNumActive(key); + } + + public void clear() throws Exception, UnsupportedOperationException { + keyedPool.clear(); + } + + public void close() throws Exception { + keyedPool.close(); + } + + public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { + keyedPool.setFactory(adapt(factory)); + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("ObjectPoolAdaptor"); + sb.append("{key=").append(key); + sb.append(", keyedPool=").append(keyedPool); + sb.append('}'); + return sb.toString(); + } + } + + private static class KeyedObjectPoolAdaptor implements KeyedObjectPool { + private final ObjectPool pool; + + KeyedObjectPoolAdaptor(final ObjectPool pool) throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + this.pool = pool; + } + + public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { + return pool.borrowObject(); + } + + public void returnObject(final Object key, final Object obj) throws Exception { + pool.returnObject(obj); + } + + public void invalidateObject(final Object key, final Object obj) throws Exception { + pool.invalidateObject(obj); + } + + public void addObject(final Object key) throws Exception, IllegalStateException { + pool.addObject(); + } + + public int getNumIdle(final Object key) throws UnsupportedOperationException { + return pool.getNumIdle(); + } + + public int getNumActive(final Object key) throws UnsupportedOperationException { + return pool.getNumActive(); + } + + public int getNumIdle() throws UnsupportedOperationException { + return pool.getNumIdle(); + } + + public int getNumActive() throws UnsupportedOperationException { + return pool.getNumActive(); + } + + public void clear() throws Exception, UnsupportedOperationException { + pool.clear(); + } + + public void clear(final Object key) throws Exception, UnsupportedOperationException { + pool.clear(); + } + + public void close() throws Exception { + pool.close(); + } + + public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { + pool.setFactory(adapt(factory)); + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("KeyedObjectPoolAdaptor"); + sb.append("{pool=").append(pool); + sb.append('}'); + return sb.toString(); + } + } + + private static class ObjectPoolMinIdleTimerTask extends TimerTask { + private final int minIdle; + private final ObjectPool pool; + + ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("poll must not be null."); + } + this.pool = pool; + this.minIdle = minIdle; + } + + public void run() { + boolean success = false; + try { + if (pool.getNumIdle() < minIdle) { + pool.addObject(); + } + success = true; + + } catch (Exception e) { + cancel(); + + } finally { + // detect other types of Throwable and cancel this Timer + if (!success) { + cancel(); + } + } + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("ObjectPoolMinIdleTimerTask"); + sb.append("{minIdle=").append(minIdle); + sb.append(", pool=").append(pool); + sb.append('}'); + return sb.toString(); + } + } + + private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask { + private final int minIdle; + private final Object key; + private final KeyedObjectPool pool; + + KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool pool, final Object key, final int minIdle) throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + this.pool = pool; + this.key = key; + this.minIdle = minIdle; + } + + public void run() { + boolean success = false; + try { + if (pool.getNumIdle(key) < minIdle) { + pool.addObject(key); + } + success = true; + + } catch (Exception e) { + cancel(); + + } finally { + // detect other types of Throwable and cancel this Timer + if (!success) { + cancel(); + } + } + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("KeyedObjectPoolMinIdleTimerTask"); + sb.append("{minIdle=").append(minIdle); + sb.append(", key=").append(key); + sb.append(", pool=").append(pool); + sb.append('}'); + return sb.toString(); + } + } + + private static class SynchronizedObjectPool implements ObjectPool { + private final Object lock; + private final ObjectPool pool; + + SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException { + if (pool == null) { + throw new IllegalArgumentException("pool must not be null."); + } + this.pool = pool; + lock = new Object(); + } + + public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { + synchronized (lock) { + return pool.borrowObject(); + } + } + + public void returnObject(final Object obj) throws Exception { + synchronized (lock) { + pool.returnObject(obj); + } + } + + public void invalidateObject(final Object obj) throws Exception { + synchronized (lock) { + pool.invalidateObject(obj); + } + } + + public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { + synchronized (lock) { + pool.addObject(); + } + } + + public int getNumIdle() throws UnsupportedOperationException { + synchronized (lock) { + return pool.getNumIdle(); + } + } + + public int getNumActive() throws UnsupportedOperationException { + synchronized (lock) { + return pool.getNumActive(); + } + } + + public void clear() throws Exception, UnsupportedOperationException { + synchronized (lock) { + pool.clear(); + } + } + + public void close() throws Exception { + synchronized (lock) { + pool.close(); + } + } + + public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { + synchronized (lock) { + pool.setFactory(factory); + } + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("SynchronizedObjectPool"); + sb.append("{pool=").append(pool); + sb.append('}'); + return sb.toString(); + } + } + + private static class SynchronizedKeyedObjectPool implements KeyedObjectPool { + private final Object lock; + private final KeyedObjectPool keyedPool; + + SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException { + if (keyedPool == null) { + throw new IllegalArgumentException("keyedPool must not be null."); + } + this.keyedPool = keyedPool; + lock = new Object(); + } + + public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { + synchronized (lock) { + return keyedPool.borrowObject(key); + } + } + + public void returnObject(final Object key, final Object obj) throws Exception { + synchronized (lock) { + keyedPool.returnObject(key, obj); + } + } + + public void invalidateObject(final Object key, final Object obj) throws Exception { + synchronized (lock) { + keyedPool.invalidateObject(key, obj); + } + } + + public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { + synchronized (lock) { + keyedPool.addObject(key); + } + } + + public int getNumIdle(final Object key) throws UnsupportedOperationException { + synchronized (lock) { + return keyedPool.getNumIdle(key); + } + } + + public int getNumActive(final Object key) throws UnsupportedOperationException { + synchronized (lock) { + return keyedPool.getNumActive(key); + } + } + + public int getNumIdle() throws UnsupportedOperationException { + synchronized (lock) { + return keyedPool.getNumIdle(); + } + } + + public int getNumActive() throws UnsupportedOperationException { + synchronized (lock) { + return keyedPool.getNumActive(); + } + } + + public void clear() throws Exception, UnsupportedOperationException { + synchronized (lock) { + keyedPool.clear(); + } + } + + public void clear(final Object key) throws Exception, UnsupportedOperationException { + synchronized (lock) { + keyedPool.clear(key); + } + } + + public void close() throws Exception { + synchronized (lock) { + keyedPool.close(); + } + } + + public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { + synchronized (lock) { + keyedPool.setFactory(factory); + } + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("SynchronizedKeyedObjectPool"); + sb.append("{keyedPool=").append(keyedPool); + sb.append('}'); + return sb.toString(); + } + } + + private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory { + private final Object lock; + private final PoolableObjectFactory factory; + + SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException { + if (factory == null) { + throw new IllegalArgumentException("factory must not be null."); + } + this.factory = factory; + lock = new Object(); + } + + public Object makeObject() throws Exception { + synchronized (lock) { + return factory.makeObject(); + } + } + + public void destroyObject(final Object obj) throws Exception { + synchronized (lock) { + factory.destroyObject(obj); + } + } + + public boolean validateObject(final Object obj) { + synchronized (lock) { + return factory.validateObject(obj); + } + } + + public void activateObject(final Object obj) throws Exception { + synchronized (lock) { + factory.activateObject(obj); + } + } + + public void passivateObject(final Object obj) throws Exception { + synchronized (lock) { + factory.passivateObject(obj); + } + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("SynchronizedPoolableObjectFactory"); + sb.append("{factory=").append(factory); + sb.append('}'); + return sb.toString(); + } + } + + private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory { + private final Object lock; + private final KeyedPoolableObjectFactory keyedFactory; + + SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException { + if (keyedFactory == null) { + throw new IllegalArgumentException("keyedFactory must not be null."); + } + this.keyedFactory = keyedFactory; + lock = new Object(); + } + + public Object makeObject(final Object key) throws Exception { + synchronized (lock) { + return keyedFactory.makeObject(key); + } + } + + public void destroyObject(final Object key, final Object obj) throws Exception { + synchronized (lock) { + keyedFactory.destroyObject(key, obj); + } + } + + public boolean validateObject(final Object key, final Object obj) { + synchronized (lock) { + return keyedFactory.validateObject(key, obj); + } + } + + public void activateObject(final Object key, final Object obj) throws Exception { + synchronized (lock) { + keyedFactory.activateObject(key, obj); + } + } + + public void passivateObject(final Object key, final Object obj) throws Exception { + synchronized (lock) { + keyedFactory.passivateObject(key, obj); + } + } + + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append("SynchronizedKeyedPoolableObjectFactory"); + sb.append("{keyedFactory=").append(keyedFactory); + sb.append('}'); + return sb.toString(); + } + } +} \ No newline at end of file Added: jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestPools .java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/trunk/src/test/org /apache/commons/pool/TestPools.java?rev=383042&view=auto ============================================================================ == --- jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestPools .java (added) +++ jakarta/commons/proper/pool/trunk/src/test/org/apache/commons/pool/TestPools .java Fri Mar 3 21:42:18 2006 @@ -0,0 +1,391 @@ +/* + * 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 junit.framework.TestCase; + +import java.lang.reflect.Proxy; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.util.List; +import java.util.ArrayList; +import java.util.Set; +import java.util.HashSet; +import java.util.TimerTask; +import java.util.Collection; +import java.util.Map; +import java.util.Iterator; + +/** + * Unit tests for [EMAIL PROTECTED] Pools}. + * + * @author Sandy McArthur + * @version $Revision$ $Date$ + */ +public class TestPools extends TestCase { + + /** Period between checks for minIdle tests. Increase this if you happen to get too many false failures. */ + private static final int CHECK_PERIOD = 300; + + /** Times to let the minIdle check run. */ + private static final int CHECK_COUNT = 4; + + /** Sleep time to let the minIdle tests run CHECK_COUNT times. */ + private static final int CHECK_SLEEP_PERIOD = CHECK_PERIOD * (CHECK_COUNT - 1) + CHECK_PERIOD / 2; + + public void testAdaptKeyedPoolableObjectFactory() throws Exception { + try { + Pools.adapt((KeyedPoolableObjectFactory)null); + fail("Pools.adapt(KeyedPoolableObjectFactory) must not allow null factory."); + } catch (IllegalArgumentException iae) { + // expected + } + } + + public void testAdaptKeyedPoolableObjectFactoryKey() throws Exception { + try { + Pools.adapt((KeyedPoolableObjectFactory)null, new Object()); + fail("Pools.adapt(KeyedPoolableObjectFactory, key) must not allow null factory."); + } catch (IllegalArgumentException iae) { + // expected + } + try { + Pools.adapt((KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFacto ry.class, null), null); + fail("Pools.adapt(KeyedPoolableObjectFactory, key) must not allow null key."); + } catch (IllegalArgumentException iae) { + // expected + } + + final List calledMethods = new ArrayList(); + final KeyedPoolableObjectFactory kpof = + (KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFactory.class, calledMethods); + + final PoolableObjectFactory pof = Pools.adapt(kpof); + pof.activateObject(null); + pof.destroyObject(null); + pof.makeObject(); + pof.passivateObject(null); + pof.validateObject(null); + + final List expectedMethods = new ArrayList(); + expectedMethods.add("activateObject"); + expectedMethods.add("destroyObject"); + expectedMethods.add("makeObject"); + expectedMethods.add("passivateObject"); + expectedMethods.add("validateObject"); + + assertEquals(expectedMethods, calledMethods); + } + + public void testAdaptPoolableObjectFactory() throws Exception { + try { + Pools.adapt((PoolableObjectFactory)null); + fail("Pools.adapt(PoolableObjectFactory) must not allow null factory."); + } catch (IllegalArgumentException iae) { + // expected + } + + final List calledMethods = new ArrayList(); + final PoolableObjectFactory pof = + (PoolableObjectFactory)createProxy(PoolableObjectFactory.class, calledMethods); + + final KeyedPoolableObjectFactory kpof = Pools.adapt(pof); + kpof.activateObject(null, null); + kpof.destroyObject(null, null); + kpof.makeObject(null); + kpof.passivateObject(null, null); + kpof.validateObject(null, null); + + final List expectedMethods = new ArrayList(); + expectedMethods.add("activateObject"); + expectedMethods.add("destroyObject"); + expectedMethods.add("makeObject"); + expectedMethods.add("passivateObject"); + expectedMethods.add("validateObject"); + + assertEquals(expectedMethods, calledMethods); + } + + public void testAdaptKeyedObjectPool() throws Exception { + try { + Pools.adapt((KeyedObjectPool)null); + fail("Pools.adapt(KeyedObjectPool) must not allow a null pool."); + } catch(IllegalArgumentException iae) { + // expected + } + } + + public void testAdaptKeyedObjectPoolKey() throws Exception { + try { + Pools.adapt((KeyedObjectPool)null, new Object()); + fail("Pools.adapt(KeyedObjectPool, key) must not allow a null pool."); + } catch(IllegalArgumentException iae) { + // expected + } + try { + Pools.adapt((KeyedObjectPool)createProxy(KeyedObjectPool.class, null), null); + fail("Pools.adapt(KeyedObjectPool, key) must not allow a null key."); + } catch(IllegalArgumentException iae) { + // expected + } + + final List calledMethods = new ArrayList(); + final KeyedObjectPool kop = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods); + + final ObjectPool op = Pools.adapt(kop); + op.addObject(); + op.borrowObject(); + op.clear(); + op.close(); + op.getNumActive(); + op.getNumIdle(); + op.invalidateObject(null); + op.returnObject(null); + op.setFactory((PoolableObjectFactory)createProxy(PoolableObjectFactory.class , null)); + + final List expectedMethods = new ArrayList(); + expectedMethods.add("addObject"); + expectedMethods.add("borrowObject"); + expectedMethods.add("clear"); + expectedMethods.add("close"); + expectedMethods.add("getNumActive"); + expectedMethods.add("getNumIdle"); + expectedMethods.add("invalidateObject"); + expectedMethods.add("returnObject"); + expectedMethods.add("setFactory"); + + assertEquals(expectedMethods, calledMethods); + } + + public void testAdaptObjectPool() throws Exception { + try { + Pools.adapt((ObjectPool)null); + fail("Pools.adapt(ObjectPool) must not allow a null pool."); + } catch(IllegalArgumentException iae) { + // expected + } + + final List calledMethods = new ArrayList(); + final ObjectPool op = (ObjectPool)createProxy(ObjectPool.class, calledMethods); + + final KeyedObjectPool kop = Pools.adapt(op); + kop.addObject(null); + kop.borrowObject(null); + kop.clear(); + kop.clear(null); + kop.close(); + kop.getNumActive(); + kop.getNumActive(null); + kop.getNumIdle(); + kop.getNumIdle(null); + kop.invalidateObject(null, null); + kop.returnObject(null, null); + kop.setFactory((KeyedPoolableObjectFactory)createProxy(KeyedPoolableObjectFa ctory.class, null)); + + final List expectedMethods = new ArrayList(); + expectedMethods.add("addObject"); + expectedMethods.add("borrowObject"); + expectedMethods.add("clear"); + expectedMethods.add("clear"); + expectedMethods.add("close"); + expectedMethods.add("getNumActive"); + expectedMethods.add("getNumActive"); + expectedMethods.add("getNumIdle"); + expectedMethods.add("getNumIdle"); + expectedMethods.add("invalidateObject"); + expectedMethods.add("returnObject"); + expectedMethods.add("setFactory"); + + assertEquals(expectedMethods, calledMethods); + } + + public void testCheckMinIdleObjectPool() throws Exception { + final List calledMethods = new ArrayList(); + final ObjectPool pool = (ObjectPool)createProxy(ObjectPool.class, calledMethods); + final TimerTask task = Pools.checkMinIdle(pool, 1, CHECK_PERIOD); // checks minIdle immediately + + Thread.sleep(CHECK_SLEEP_PERIOD); // will check CHECK_COUNT more times. + task.cancel(); + + final List expectedMethods = new ArrayList(); + for (int i=0; i < CHECK_COUNT; i++) { + expectedMethods.add("getNumIdle"); + expectedMethods.add("addObject"); + } + assertEquals(expectedMethods, calledMethods); // may fail because of the thread scheduler + } + + public void testCheckMinIdleKeyedObjectPool() throws Exception { + final List calledMethods = new ArrayList(); + final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods); + final Object key = new Object(); + final TimerTask task = Pools.checkMinIdle(pool, key, 1, CHECK_PERIOD); // checks minIdle immediately + + Thread.sleep(CHECK_SLEEP_PERIOD); // will check CHECK_COUNT more times. + task.cancel(); + + final List expectedMethods = new ArrayList(); + for (int i=0; i < CHECK_COUNT; i++) { + expectedMethods.add("getNumIdle"); + expectedMethods.add("addObject"); + } + assertEquals(expectedMethods, calledMethods); // may fail because of the thread scheduler + } + + public void testCheckMinIdleKeyedObjectPoolKeys() throws Exception { + final List calledMethods = new ArrayList(); + final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods); + final Collection keys = new ArrayList(2); + keys.add("one"); + keys.add("two"); + final Map tasks = Pools.checkMinIdle(pool, keys, 1, CHECK_PERIOD); // checks minIdle immediately + + Thread.sleep(CHECK_SLEEP_PERIOD); // will check CHECK_COUNT more times. + final Iterator iter = tasks.values().iterator(); + while (iter.hasNext()) { + final TimerTask task = (TimerTask)iter.next(); + task.cancel(); + } + + final List expectedMethods = new ArrayList(); + for (int i=0; i < CHECK_COUNT * keys.size(); i++) { + expectedMethods.add("getNumIdle"); + expectedMethods.add("addObject"); + } + assertEquals(expectedMethods, calledMethods); // may fail because of the thread scheduler + } + + public void testPrefillObjectPool() throws Exception { + final List calledMethods = new ArrayList(); + final ObjectPool pool = (ObjectPool)createProxy(ObjectPool.class, calledMethods); + + Pools.prefill(pool, 0); + final List expectedMethods = new ArrayList(); + assertEquals(expectedMethods, calledMethods); + + calledMethods.clear(); + Pools.prefill(pool, 3); + for (int i=0; i < 3; i++) { + expectedMethods.add("addObject"); + } + assertEquals(expectedMethods, calledMethods); + } + + public void testPrefillKeyedObjectPool() throws Exception { + final List calledMethods = new ArrayList(); + final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods); + + Pools.prefill(pool, new Object(), 0); + final List expectedMethods = new ArrayList(); + assertEquals(expectedMethods, calledMethods); + + calledMethods.clear(); + Pools.prefill(pool, new Object(), 3); + for (int i=0; i < 3; i++) { + expectedMethods.add("addObject"); + } + assertEquals(expectedMethods, calledMethods); + } + + public void testPrefillKeyedObjectPoolCollection() throws Exception { + final List calledMethods = new ArrayList(); + final KeyedObjectPool pool = (KeyedObjectPool)createProxy(KeyedObjectPool.class, calledMethods); + + final Set keys = new HashSet(); + Pools.prefill(pool, keys, 0); + final List expectedMethods = new ArrayList(); + assertEquals(expectedMethods, calledMethods); + + calledMethods.clear(); + keys.add(new Integer(1)); + keys.add("two"); + keys.add(new Double(3.1415926)); + Pools.prefill(pool, keys, 3); + for (int i=0; i < keys.size() * 3; i++) { + expectedMethods.add("addObject"); + } + assertEquals(expectedMethods, calledMethods); + } + + public void testSynchronizedPoolObjectPool() throws Exception { + try { + Pools.synchronizedPool((ObjectPool)null); + fail("Pools.synchronizedPool(ObjectPool) must not allow a null pool."); + } catch(IllegalArgumentException iae) { + // expected + } + // TODO: Anyone feel motivated to construct a test that verifies proper synchronization? + } + + public void testSynchronizedPoolKeyedObjectPool() throws Exception { + try { + Pools.synchronizedPool((KeyedObjectPool)null); + fail("Pools.synchronizedPool(KeyedObjectPool) must not allow a null pool."); + } catch(IllegalArgumentException iae) { + // expected + } + // TODO: Anyone feel motivated to construct a test that verifies proper synchronization? + } + + public void testSynchronizedPoolableFactoryPoolableObjectFactory() throws Exception { + try { + Pools.synchronizedPoolableFactory((PoolableObjectFactory)null); + fail("Pools.synchronizedPoolableFactory(PoolableObjectFactory) must not allow a null factory."); + } catch(IllegalArgumentException iae) { + // expected + } + // TODO: Anyone feel motivated to construct a test that verifies proper synchronization? + } + + public void testSynchronizedPoolableFactoryKeyedPoolableObjectFactory() throws Exception { + try { + Pools.synchronizedPoolableFactory((KeyedPoolableObjectFactory)null); + fail("Pools.synchronizedPoolableFactory(KeyedPoolableObjectFactory) must not allow a null factory."); + } catch(IllegalArgumentException iae) { + // expected + } + // TODO: Anyone feel motivated to construct a test that verifies proper synchronization? + } + + private static Object createProxy(final Class clazz, final List logger) { + return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, + new MethodCallLogger(logger)); + } + + private static class MethodCallLogger implements InvocationHandler { + private final List calledMethods; + + MethodCallLogger(final List calledMethods) { + this.calledMethods = calledMethods; + } + + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + calledMethods.add(method.getName()); + if (boolean.class.equals(method.getReturnType())) { + return Boolean.FALSE; + } else if (int.class.equals(method.getReturnType())) { + return new Integer(0); + } else if (long.class.equals(method.getReturnType())) { + return new Long(0); + } else if (Object.class.equals(method.getReturnType())) { + return new Object(); + } else { + return null; + } + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
