java/org/mcarthur/ 0000755 0000765 0000765 00000000000 10330715630 016043 5 ustar sandymac sandymac 0000000 0000000 java/org/mcarthur/sandy/ 0000755 0000765 0000765 00000000000 10330715630 017161 5 ustar sandymac sandymac 0000000 0000000 java/org/mcarthur/sandy/commons/ 0000755 0000765 0000765 00000000000 10330715630 020634 5 ustar sandymac sandymac 0000000 0000000 java/org/mcarthur/sandy/commons/pool/ 0000755 0000765 0000765 00000000000 10335157561 021615 5 ustar sandymac sandymac 0000000 0000000 java/org/mcarthur/sandy/commons/pool/composite/ 0000755 0000765 0000765 00000000000 10373533745 023623 5 ustar sandymac sandymac 0000000 0000000 java/org/mcarthur/sandy/commons/pool/composite/AbstractLender.java 0000644 0000765 0000765 00000004373 10373450630 027361 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.util.List;
import java.util.ListIterator;
/**
* A base {@link Lender} implementation that provides the common implementations of methods.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
abstract class AbstractLender implements Lender, Serializable {
private static final long serialVersionUID = -1338771389484034430L;
/**
* CompositeObjectPool this {@link Lender} is associated with.
*/
private CompositeObjectPool objectPool;
public void setCompositeObjectPool(final CompositeObjectPool objectPool) throws IllegalArgumentException, IllegalStateException {
if (objectPool == null) {
throw new IllegalArgumentException("objectPool must not be null.");
}
if (this.objectPool != null) {
throw new IllegalStateException("Manager cannot be reattached.");
}
this.objectPool = objectPool;
}
public abstract Object borrow();
public void repay(final Object obj) {
final List pool = getObjectPool().getPool();
assert Thread.holdsLock(pool);
pool.add(obj);
pool.notifyAll();
}
public ListIterator listIterator() {
return getObjectPool().getPool().listIterator();
}
public int size() {
return getObjectPool().getPool().size();
}
/**
* Get the CompositeObjectPool this {@link Lender} is associated with.
*
* @return the CompositeObjectPool this {@link Lender} is associated with.
*/
protected CompositeObjectPool getObjectPool() {
return objectPool;
}
} java/org/mcarthur/sandy/commons/pool/composite/AbstractManager.java 0000644 0000765 0000765 00000005774 10373003300 027514 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* A base {@link Manager} implementation that provides the common implementations of methods.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
abstract class AbstractManager implements Manager, Serializable {
private static final long serialVersionUID = -1729636795986138892L;
/**
* CompositeObjectPool this {@link Lender} is associated with.
*/
protected CompositeObjectPool objectPool;
/**
* Called once to associate this manager with an object pool by the {@link CompositeObjectPool} constructor.
*
* @param objectPool the pool to associate with.
* @throws IllegalArgumentException if objectPool
is null
.
* @throws IllegalStateException if this method is called more than once.
*/
public void setCompositeObjectPool(final CompositeObjectPool objectPool) {
if (this.objectPool != null) {
throw new IllegalStateException("Manager cannot be reattached.");
}
if (objectPool == null) {
throw new IllegalArgumentException("objectPool must not be null.");
}
this.objectPool = objectPool;
}
/**
* Retreives the next object from the pool. Objects from the pool will be
* {@link PoolableObjectFactory#activateObject(Object) activated} and
* {@link PoolableObjectFactory#validateObject(Object) validated}.
* Newly {@link PoolableObjectFactory#makeObject() created} objects will not be activated or validated.
*
* @return a new or activated object.
* @throws NoSuchElementException if the pool is empty and no new object can be created.
* @throws Exception usually from {@link PoolableObjectFactory} methods.
*/
public abstract Object nextFromPool() throws Exception;
/**
* Return an object to the pool. Object will be {@link PoolableObjectFactory#passivateObject(Object) passivated}.
*
* @param obj the object to return to the pool.
* @throws Exception as thrown by {@link PoolableObjectFactory#passivateObject(Object)}.
*/
public void returnToPool(final Object obj) throws Exception {
assert Thread.holdsLock(objectPool.getPool());
objectPool.getLender().repay(obj);
}
} java/org/mcarthur/sandy/commons/pool/composite/ActiveLimitManager.java 0000644 0000765 0000765 00000004011 10373434706 030164 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
/**
* Base class for all {@link Manager}s that limit the number of active objects associate with the pool.
*
* @see LimitBehavior
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
abstract class ActiveLimitManager extends DelegateManager implements Serializable {
private static final long serialVersionUID = 917380099264820020L;
/**
* Maximum number of objects activated from this object pool at one time.
*/
private int maxActive = 0;
/**
* Create a manager that limits the number of active objects borrowed from the pool.
*
* @param delegate the manager to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
protected ActiveLimitManager(final Manager delegate) throws IllegalArgumentException {
super(delegate);
}
/**
* Maximum number of active objects from this pool.
*
* @return maximum number of active objects from this pool.
*/
protected final int getMaxActive() {
return maxActive;
}
/**
* Maximum number of active objects from this pool.
*
* @param maxActive maximum number of active objects from this pool.
*/
final void setMaxActive(final int maxActive) {
this.maxActive = maxActive;
}
} java/org/mcarthur/sandy/commons/pool/composite/BorrowType.java 0000644 0000765 0000765 00000006274 10373003300 026566 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.ObjectPool;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.ref.SoftReference;
/**
* Specifies the order in which objects are borrowed and returned to the pool.
*
* @see CompositeObjectPoolFactory#setBorrowType(BorrowType)
* @see CompositeKeyedObjectPoolFactory#setBorrowType(BorrowType)
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
public final class BorrowType implements Serializable {
private static final long serialVersionUID = 3357921765798594792L;
/**
* Objects are returned from the pool in the order they are added to the pool.
*/
public static final BorrowType FIFO = new BorrowType("FIFO");
/**
* The most recently returned object is the first one returned when an object is borrowed.
*/
public static final BorrowType LIFO = new BorrowType("LIFO");
/**
* Like {@link #FIFO} but idle objects are wrapped in a {@link SoftReference} to allow possible garbage
* collection. Idle objects collected by the garbage collector will not be
* {@link ObjectPool#invalidateObject(Object) invalidated} like normal.
*/
public static final BorrowType SOFT_FIFO = new BorrowType("SOFT_FIFO");
/**
* Like {@link #LIFO} but idle objects are wrapped in a {@link SoftReference} to allow possible garbage
* collection. Idle objects collected by the garbage collector will not be
* {@link ObjectPool#invalidateObject(Object) invalidated} like normal.
*/
public static final BorrowType SOFT_LIFO = new BorrowType("SOFT_LIFO");
/**
* Never returns an object from the pool nor returns one to the pool. This basicly turns the pool into a factory,
* it may have some utility if used with {@link CompositeObjectPoolFactory#setMaxActive(int) maxActive}.
* This is not compatible with {@link ExhaustionBehavior#FAIL}.
*/
public static final BorrowType NULL = new BorrowType("NULL");
/**
* enum name.
*/
private final String name;
private BorrowType(final String name) {
this.name = name;
}
public String toString() {
return name;
}
// Autogenerated with Java 1.5 enums
public static BorrowType[] values() {
return new BorrowType[] {NULL, FIFO, LIFO, SOFT_FIFO, SOFT_LIFO};
}
// necessary for serialization
private static int nextOrdinal = 0;
private final int ordinal = nextOrdinal++;
private Object readResolve() throws ObjectStreamException {
return values()[ordinal];
}
} java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPool.java 0000644 0000765 0000765 00000042516 10373423664 031401 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.KeyedObjectPool;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.ObjectPoolFactory;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A keyed object pool that is basically implemented as a map of object pools. Almost all the functionality in this
* implementation derives from an {@link ObjectPoolFactory} that creates {@link ObjectPool}s as needed to be associated
* with a key.
*
*
Instances of this class should only be instantiated by {@link CompositeKeyedObjectPoolFactory} or other * package-local classes that are intimately familiar with it's proper usage.
* * @see CompositeObjectPoolFactory * @author Sandy McArthur * @since #.# * @version $Revision$ $Date$ */ final class CompositeKeyedObjectPool implements KeyedObjectPool, Cloneable, Serializable { private static final long serialVersionUID = -5886463772111164686L; /** * Map of keys to {@link ObjectPool}s. */ private final Map objectPools = new HashMap(); /** * Object pool factory used to create new object pools as needed. */ // XXX: Add better handling of when this instance is not Serializable private final ObjectPoolFactory poolFactory; /** * Thread local used to pass keys through an object pool to a {@link KeyedPoolableObjectFactory}. * If this is null it means a {@link KeyedPoolableObjectFactoryAdapter} * is not being used and this isn't needed. */ private final transient ThreadLocal keys; /** * Is this object pool still open. */ private volatile boolean open = true; CompositeKeyedObjectPool(final ObjectPoolFactory poolFactory) throws IllegalArgumentException { if (poolFactory == null) { throw new IllegalArgumentException("object pool factory must not be null."); } this.poolFactory = poolFactory; if (poolFactory instanceof CompositeObjectPoolFactory) { final PoolableObjectFactory pof = ((CompositeObjectPoolFactory)poolFactory).getFactory(); if (pof instanceof KeyedPoolableObjectFactoryAdapter) { keys = new ThreadLocal(); ((KeyedPoolableObjectFactoryAdapter)pof).setCompositeKeyedObjectPool(this); } else { keys = null; } } else { keys = null; } } /** * Get or create an object pool for thekey
.
*
* @param key which object pool to get or create.
* @return the object pool for key
.
*/
private ObjectPool getObjectPool(final Object key) {
ObjectPool pool;
synchronized (objectPools) {
pool = (ObjectPool)objectPools.get(key);
if (pool == null) {
pool = poolFactory.createPool();
objectPools.put(key, pool);
}
}
return pool;
}
/**
* Obtain an instance from my pool
* for the specified key.
* By contract, clients MUST return
* the borrowed object using
* {@link #returnObject(Object,Object) returnObject},
* or a related method as defined in an implementation
* or sub-interface,
* using a key that is equivalent to the one used to
* borrow the instance in the first place.
*
* @param key the key used to obtain the object
* @return an instance from my pool.
* @throws Exception if there is an unexpected problem.
*/
public Object borrowObject(final Object key) throws Exception {
assertOpen();
final ObjectPool pool = getObjectPool(key);
try {
if (keys != null) {
keys.set(key);
}
return pool.borrowObject();
} finally {
if (keys != null) {
keys.set(null); // unset key
}
}
}
/**
* Return an instance to my pool.
* By contract, obj MUST have been obtained
* using {@link #borrowObject(Object) borrowObject}
* or a related method as defined in an implementation
* or sub-interface
* using a key that is equivalent to the one used to
* borrow the Object in the first place.
*
* @param key the key used to obtain the object
* @param obj a {@link #borrowObject(Object) borrowed} instance to be returned.
* @throws Exception if there is an unexpected problem.
*/
public void returnObject(final Object key, final Object obj) throws Exception {
assertOpen();
final ObjectPool pool = getObjectPool(key);
try {
if (keys != null) {
keys.set(key);
}
pool.returnObject(obj);
} finally {
if (keys != null) {
keys.set(null); // unset key
}
}
}
/**
* Invalidates an object from the pool
* By contract, obj MUST have been obtained
* using {@link #borrowObject borrowObject}
* or a related method as defined in an implementation
* or sub-interface
* using a key that is equivalent to the one used to
* borrow the Object in the first place.
* * This method should be used when an object that has been borrowed * is determined (due to an exception or other problem) to be invalid. * If the connection should be validated before or after borrowing, * then the {@link PoolableObjectFactory#validateObject} method should be * used instead. * * @param key the key used to obtain the object * @param obj a {@link #borrowObject borrowed} instance to be returned. * @throws Exception if there is an unexpected problem. */ public void invalidateObject(final Object key, final Object obj) throws Exception { assertOpen(); final ObjectPool pool = getObjectPool(key); try { if (keys != null) { keys.set(key); } pool.invalidateObject(obj); } finally { if (keys != null) { keys.set(null); // unset key } } } /** * Create an object using my {@link #setFactory factory} or other * implementation dependent mechanism, and place it into the pool. * addObject() is useful for "pre-loading" a pool with idle objects. * (Optional operation). * * @param key the key used to obtain the object * @throws Exception if there is an unexpected problem. */ public void addObject(final Object key) throws Exception { assertOpen(); final ObjectPool pool = getObjectPool(key); try { if (keys != null) { keys.set(key); } pool.addObject(); } finally { if (keys != null) { keys.set(null); // unset key } } } /** * Returns the number of instances * corresponding to the given key * currently idle in my pool (optional operation). * Throws {@link UnsupportedOperationException} * if this information is not available. * * @param key the key * @return the number of instances corresponding to the given key currently idle in my pool * @throws UnsupportedOperationException when this implementation doesn't support the operation */ public int getNumIdle(final Object key) throws UnsupportedOperationException { assertOpen(); final ObjectPool pool = getObjectPool(key); try { if (keys != null) { keys.set(key); } return pool.getNumIdle(); } finally { if (keys != null) { keys.set(null); // unset key } } } /** * Returns the number of instances * currently borrowed from but not yet returned * to my pool corresponding to the * given key (optional operation). * Throws {@link UnsupportedOperationException} * if this information is not available. * * @param key the key * @return the number of instances corresponding to the given key currently borrowed in my pool * @throws UnsupportedOperationException when this implementation doesn't support the operation */ public int getNumActive(final Object key) throws UnsupportedOperationException { assertOpen(); final ObjectPool pool = getObjectPool(key); try { if (keys != null) { keys.set(key); } return pool.getNumActive(); } finally { if (keys != null) { keys.set(null); // unset key } } } /** * Returns the total number of instances * currently idle in my pool (optional operation). * Throws {@link UnsupportedOperationException} * if this information is not available. * * @return the total number of instances currently idle in my pool * @throws UnsupportedOperationException when this implementation doesn't support the operation */ public int getNumIdle() throws UnsupportedOperationException { assertOpen(); int numIdle = 0; synchronized (objectPools) { final Iterator iter = objectPools.values().iterator(); while (iter.hasNext()) { final ObjectPool pool = (ObjectPool)iter.next(); numIdle += pool.getNumIdle(); } } return numIdle; } /** * Returns the total number of instances * current borrowed from my pool but not * yet returned (optional operation). * Throws {@link UnsupportedOperationException} * if this information is not available. * * @return the total number of instances currently borrowed from my pool * @throws UnsupportedOperationException when this implementation doesn't support the operation */ public int getNumActive() throws UnsupportedOperationException { assertOpen(); int numActive = 0; synchronized (objectPools) { final Iterator iter = objectPools.values().iterator(); while (iter.hasNext()) { final ObjectPool pool = (ObjectPool)iter.next(); numActive += pool.getNumActive(); } } return numActive; } /** * Clears my pool, removing all pooled instances * (optional operation). * Throws {@link UnsupportedOperationException} * if the pool cannot be cleared. * * @throws UnsupportedOperationException when this implementation doesn't support the operation * @throws Exception if there is an unexpected problem. */ public void clear() throws Exception, UnsupportedOperationException { synchronized (objectPools) { final Iterator iter = objectPools.values().iterator(); while (iter.hasNext()) { final ObjectPool pool = (ObjectPool)iter.next(); pool.clear(); } } } /** * Clears the specified pool, removing all * pooled instances corresponding to * the given key (optional operation). * Throws {@link UnsupportedOperationException} * if the pool cannot be cleared. * * @param key the key to clear * @throws UnsupportedOperationException when this implementation doesn't support the operation * @throws Exception if there is an unexpected problem. */ public void clear(final Object key) throws Exception, UnsupportedOperationException { assertOpen(); final ObjectPool pool = getObjectPool(key); try { if (keys != null) { keys.set(key); } pool.clear(); } finally { if (keys != null) { keys.set(null); // unset key } } } /** * Close this pool, and free any resources associated with it. * * @throws Exception if there is an unexpected problem. */ public void close() throws Exception { open = false; Thread.yield(); // encourage any threads currently executing in the pool to finish first. synchronized (objectPools) { final Iterator iter = objectPools.values().iterator(); while (iter.hasNext()) { final ObjectPool pool = (ObjectPool)iter.next(); pool.close(); iter.remove(); } } } /** * Sets the {@link KeyedPoolableObjectFactory factory} I use * to create new instances (optional operation). * @param factory the {@link KeyedPoolableObjectFactory} I use to create new instances. * @throws IllegalStateException when the factory cannot be set at this time * @throws UnsupportedOperationException when this implementation doesn't support the operation */ public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { throw new UnsupportedOperationException("Replacing the factory not supported. Create a new pool instance instead."); } /** * Throws an {@link IllegalStateException} when the pool has been closed. * This should not be called by methods that are for returning objects to the pool. * It's better to silently discard those objects over interupting program flow. * * @throws IllegalStateException when the pool has been closed. */ private void assertOpen() throws IllegalStateException { if (!open) { throw new IllegalStateException("keyed pool has been closed."); } } /** * Return a thread local with this thread's current key. This is needed by {@link KeyedPoolableObjectFactoryAdapter} * so it can adapt a {@link KeyedPoolableObjectFactory} for use with an {@link ObjectPool} which needs a * {@link PoolableObjectFactory}. * * @return a ThreadLocal with the current key for this thread. */ ThreadLocal getKeys() { return keys; } public String toString() { final StringBuffer sb = new StringBuffer(128); sb.append("CompositeKeyedObjectPool{"); sb.append("poolFactory=").append(poolFactory); sb.append(", open=").append(open); try { final int numActive = getNumActive(); sb.append(", activeObjects=").append(numActive); } catch (Exception e) { // ignored } try { final int numIdle = getNumIdle(); sb.append(", idleObjects=").append(numIdle); } catch (Exception e) { // ignored } sb.append('}'); return sb.toString(); } /** * Creates a new keyed object pool with the same settings as this one. The new instance will not contian any * existing idle objects nor should you return active objects to it. * * @return a new keyed object pool with the same settings. */ public Object clone() throws CloneNotSupportedException { if (!getClass().equals(CompositeKeyedObjectPool.class)) { throw new CloneNotSupportedException("Subclasses must not call super.clone()"); } if (poolFactory instanceof CompositeObjectPoolFactory) { final PoolableObjectFactory pof = ((CompositeObjectPoolFactory)poolFactory).getFactory(); if (pof instanceof KeyedPoolableObjectFactoryAdapter) { final KeyedPoolableObjectFactory kopf = ((KeyedPoolableObjectFactoryAdapter)pof).getDelegate(); final CompositeObjectPoolFactory opf = (CompositeObjectPoolFactory)((CompositeObjectPoolFactory)poolFactory).clone(); opf.setFactory(new KeyedPoolableObjectFactoryAdapter(kopf)); return new CompositeKeyedObjectPool(opf); } } return new CompositeKeyedObjectPool(poolFactory); } /** * The {@link ThreadLocal} keys is not serializable and final, must create a new instance for this to be correct. */ private Object readResolve() throws ObjectStreamException { final CompositeKeyedObjectPool pool = new CompositeKeyedObjectPool(poolFactory); if (!open) { try { pool.close(); } catch (Exception e) { // don't know how this could happen... final InvalidObjectException ioe = new InvalidObjectException("pool close failed on serialized closed pool."); ioe.initCause(e); throw ioe; } } return pool; } } java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPoolFactory.java 0000644 0000765 0000765 00000041244 10373212343 032714 0 ustar sandymac sandymac 0000000 0000000 /* * 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.mcarthur.sandy.commons.pool.composite; import org.apache.commons.pool.KeyedObjectPool; import org.apache.commons.pool.KeyedObjectPoolFactory; import org.apache.commons.pool.KeyedPoolableObjectFactory; import org.apache.commons.pool.ObjectPool; import org.apache.commons.pool.ObjectPoolFactory; import org.apache.commons.pool.PoolableObjectFactory; import java.io.Serializable; /** * {@link KeyedObjectPoolFactory} that builds a custom {@link KeyedObjectPool} via composition of custom * {@link ObjectPool}s. * *
Note: Currently the default values and behavior is effectivly inherited from {@link CompositeObjectPoolFactory}, * review it if you are uncertian about the behavior of this factory. Future verions of this factory may not inherit * behavior from the {@link CompositeObjectPoolFactory}. *
* * @see CompositeObjectPoolFactory * @see BorrowType * @see ExhaustionBehavior * @see LimitBehavior * @see TrackingType * @author Sandy McArthur * @since #.# * @version $Revision$ $Date$ */ public final class CompositeKeyedObjectPoolFactory implements KeyedObjectPoolFactory, Cloneable, Serializable { private static final long serialVersionUID = 4099516083825584165L; /** * Factory to create {@link ObjectPool}s to back key. */ private final CompositeObjectPoolFactory factory; /** * Create a new keyed object pool factory witht he specific keyed object factory. * * @param factory the keyed object factory for this pool, must not be null. * @throws IllegalArgumentException iffactory
is null
.
* @see #setKeyedFactory(KeyedPoolableObjectFactory)
*/
public CompositeKeyedObjectPoolFactory(final KeyedPoolableObjectFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("keyed poolable object factory must not be null.");
}
this.factory = new CompositeObjectPoolFactory(new KeyedPoolableObjectFactoryAdapter(factory));
}
/**
* Create a new keyed object pool factory with the specific object factory. This is a convenience constructor for
* when you have a {@link PoolableObjectFactory} but want a {@link KeyedObjectPool} and the
* {@link PoolableObjectFactory object factory} doesn't care about the key.
*
* @param factory the object factory for this pool, must not be null.
* @throws IllegalArgumentException if factory
is null
.
* @see #setFactory(PoolableObjectFactory)
*/
public CompositeKeyedObjectPoolFactory(final PoolableObjectFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("poolable object factory must not be null.");
}
this.factory = new CompositeObjectPoolFactory(factory);
}
/**
* Create a new keyed object pool factory that uses a {@link CompositeObjectPoolFactory} to create
* {@link ObjectPool}s for each key.
*
* @param factory the object factory to back this keyed object factory.
* @throws IllegalArgumentException if factory
is null
.
*/
public CompositeKeyedObjectPoolFactory(final CompositeObjectPoolFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("composite object pool factory must not be null.");
}
try {
this.factory = (CompositeObjectPoolFactory)factory.clone();
} catch (CloneNotSupportedException cnse) {
// should never happen
final IllegalArgumentException iae = new IllegalArgumentException("factory must support cloning.");
iae.initCause(cnse);
throw iae;
}
}
/**
* Create a new {@link KeyedObjectPool}.
*
* @return a new {@link KeyedObjectPool}
*/
public KeyedObjectPool createPool() {
try {
// backing factory must be cloned else changing this factory's
// settings would affect previously created keyed object pools
return new CompositeKeyedObjectPool((ObjectPoolFactory)factory.clone());
} catch (CloneNotSupportedException cnse) {
final IllegalStateException ise = new IllegalStateException("backing object pool factory doesn't support cloning.");
ise.initCause(cnse);
throw ise;
}
}
/**
* Create a new {@link KeyedObjectPool} that uses an {@link ObjectPoolFactory} to create an internal
* {@link ObjectPool} to back each key. Use of this method is generally discouraged but it could be used to do some
* generally funky and intersting things.
*
* There are no guarentees the {@link KeyedObjectPool} returned by this method will behave in previously * guarenteed way. Use at your own risk.
* * @param factory the object pool factory that creates object pools to back each key. * @return a keyed object pool that uses an object pool factory to create object pools to back each key. * @throws IllegalArgumentException iffactory
is null
.
*/
public static KeyedObjectPool createPool(final ObjectPoolFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("object pool factory must not be null.");
}
return new CompositeKeyedObjectPool(factory);
}
/**
* Keyed object factory or null. This returns null in the case that this pool factory is configured to use a
* {@link PoolableObjectFactory} in which case you should use {@link #getFactory()}.
*
* @return keyed object factory or null if this factory is using a {@link PoolableObjectFactory}.
*/
public KeyedPoolableObjectFactory getKeyedFactory() {
final PoolableObjectFactory pof = factory.getFactory();
if (pof instanceof KeyedPoolableObjectFactoryAdapter) {
return ((KeyedPoolableObjectFactoryAdapter)pof).getDelegate();
}
return null;
}
/**
* The keyed object factory used by keyed object pools crated by this factory. Calling this clears any value
* previously set via {@link #setFactory(PoolableObjectFactory)}.
*
* @param factory the keyed object factory used by created keyed object pools.
* @throws IllegalArgumentException if factory
is null
.
* @see #CompositeKeyedObjectPoolFactory(KeyedPoolableObjectFactory)
*/
public void setKeyedFactory(final KeyedPoolableObjectFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("keyed object factory must not be null.");
}
setFactory(new KeyedPoolableObjectFactoryAdapter(factory));
}
/**
* Object factory or null. This returns null in the case that this pool factory is configured to use a
* {@link KeyedPoolableObjectFactory} in which case you should use {@link #getKeyedFactory()}.
*
* @return object factory or null if this factory is using a {@link KeyedPoolableObjectFactory}.
*/
public PoolableObjectFactory getFactory() {
final PoolableObjectFactory pof = factory.getFactory();
if (pof instanceof KeyedPoolableObjectFactoryAdapter) {
return null;
}
return pof;
}
/**
* The object factory used by keyed object pools created by this factory. The key will be ignored. Calling this
* clears any value previously set via {@link #setKeyedFactory(KeyedPoolableObjectFactory)}.
*
* @param factory the object factory used by created keyed object pools.
* @throws IllegalArgumentException if factory
is null
.
* @see #CompositeKeyedObjectPoolFactory(PoolableObjectFactory)
*/
public void setFactory(final PoolableObjectFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("poolable object factory must not be null.");
}
this.factory.setFactory(factory);
}
/**
* Order in which objects are borrowed from the pool.
*
* @return the order in which objects are pooled.
*/
public BorrowType getBorrowType() {
return factory.getBorrowType();
}
/**
* Set the order in which objects are borrowed from the pool.
*
* @param borrowType the order in which objects are pooled.
* @throws IllegalArgumentException when borrowType
is null
.
*/
public void setBorrowType(final BorrowType borrowType) throws IllegalArgumentException {
factory.setBorrowType(borrowType);
}
/**
* Behavior of the pool when all idle objects have been exhasted.
*
* @return behavior of the pool when all idle objects have been exhasted.
*/
public ExhaustionBehavior getExhaustionBehavior() {
return factory.getExhaustionBehavior();
}
/**
* Set the behavior for when the pool is exhausted of any idle objects.
*
* @param exhaustionBehavior the desired exhausted behavior of the pool.
* @throws IllegalArgumentException when exhaustionBehavior
is null
.
*/
public void setExhaustionBehavior(final ExhaustionBehavior exhaustionBehavior) throws IllegalArgumentException {
factory.setExhaustionBehavior(exhaustionBehavior);
}
/**
* Maximum number of idle objects in the pool.
* A negative value means unlimited.
* Zero means the pool will behave like a factory.
* A positve value limits the number of idle objects.
*
* @return a non-negative value is the maximum number of idle objects in the pool, else unlimited.
*/
public int getMaxIdle() {
return factory.getMaxIdle();
}
/**
* Set the maximum number of idle objects in the pool.
* A negative value means unlimited.
* Zero means the pool will behave like a factory.
* A positve value limits the number of idle objects.
*
* @param maxIdle a non-negative value is the maximum number of idle objects in the pool, else unlimited.
*/
public void setMaxIdle(final int maxIdle) {
factory.setMaxIdle(maxIdle);
}
/**
* Maximum number of active objects borrowed from this pool. A non-positive value means there is no limit.
*
* @return if > 0 the the maximum number of active objects else unlimited.
*/
public int getMaxActive() {
return factory.getMaxActive();
}
/**
* Set the maximum active objects borrowed from this pool. Any non-positive value means there is no limit.
*
* @param maxActive the limit of active objects from the pool or <= 0 for unlimited.
*/
public void setMaxActive(final int maxActive) {
factory.setMaxActive(maxActive);
}
/**
* Behavior of the pool when the limit of active objects has been reached.
*
* @return the behavior of the pool when the limit of active objects has been reached.
* @see #getMaxWaitMillis()
*/
public LimitBehavior getLimitBehavior() {
return factory.getLimitBehavior();
}
/**
* Set the behavior of when the pool's limit of active objects has been reached.
*
* @param limitBehavior action to take if the pool has an active object limit and is exhausted.
* @throws IllegalArgumentException when limitBehavior
is null
.
* @see #setMaxWaitMillis(int)
*/
public void setLimitBehavior(final LimitBehavior limitBehavior) throws IllegalArgumentException {
factory.setLimitBehavior(limitBehavior);
}
/**
* Wait time in milli-seconds for an object to become available to the pool when the {@link LimitBehavior#WAIT WAIT}
* {@link #setLimitBehavior(LimitBehavior) limit behavior} is used.
*
* @return the wait time for an object to become available to the pool.
* @see #getLimitBehavior()
*/
public int getMaxWaitMillis() {
return factory.getMaxWaitMillis();
}
/**
* Set the wait time in milli-seconds for an object to become available to the pool when it was exhausted.
* This has no effect unless the {@link #setLimitBehavior(LimitBehavior) limit behavior}
* is set to {@link LimitBehavior#WAIT}.
*
* @param maxWaitMillis the milli-seconds to wait for an available object in the pool or <= 0 for no limit.
* @see #setLimitBehavior(LimitBehavior)
*/
public void setMaxWaitMillis(final int maxWaitMillis) {
factory.setMaxWaitMillis(maxWaitMillis);
}
/**
* Type of tracking for active objects while they are borrowed from the pool.
*
* @return Type of tracking for active objects while they are borrowed from the pool.
*/
public TrackingType getTrackerType() {
return factory.getTrackerType();
}
/**
* Set the type of tracking for active objects while they are borrowed from the pool.
*
* @param trackerType type of tracking for active objects.
* @throws IllegalArgumentException when trackerType
is null
.
*/
public void setTrackerType(final TrackingType trackerType) throws IllegalArgumentException {
factory.setTrackerType(trackerType);
}
/**
* Are objects validated when they are returned to the pool.
*
* @return are objects validated when they are returned to the pool.
*/
public boolean isValidateOnReturn() {
return factory.isValidateOnReturn();
}
/**
* Set if objects should be validated when returned to the pool.
*
* @param validateOnReturn true
to validate objects when they are added to the pool.
*/
public void setValidateOnReturn(final boolean validateOnReturn) {
factory.setValidateOnReturn(validateOnReturn);
}
/**
* Idle timeout for idle objects to be evicted.
* A non-positive value means do not evict objects just because they are idle.
*
* @return if positive the time in milli-seconds to evict idle objects.
*/
public long getEvictIdleMillis() {
return factory.getEvictIdleMillis();
}
/**
* Set the idle timeout for idle objects to be evicted.
* A non-positive value means do not evict objects just because they are idle.
*
* @param evictIdleMillis if positive the time in milli-seconds to evict idle objects.
*/
public void setEvictIdleMillis(final long evictIdleMillis) {
factory.setEvictIdleMillis(evictIdleMillis);
}
/**
* Frequency idle objects should be checked to be still valid.
* A non-positive value means do not evict objects just because they fail to validate.
*
* @return if positive the frequency in milli-seconds to check that idle objects are still valid.
*/
public long getEvictInvalidFrequencyMillis() {
return factory.getEvictInvalidFrequencyMillis();
}
/**
* Set the frequency idle objects should be checked to be still valid.
* A non-positive value means do not evict objects just because they fail to validate.
*
* @param evictInvalidFrequencyMillis if positive the frequency in milli-seconds to check that
* idle objects are still valid.
*/
public void setEvictInvalidFrequencyMillis(final long evictInvalidFrequencyMillis) {
factory.setEvictInvalidFrequencyMillis(evictInvalidFrequencyMillis);
}
public String toString() {
return "CompositeKeyedObjectPoolFactory{" +
"factory=" + factory +
'}';
}
/**
* A copy of this factory with the same settings.
*
* @return a copy of this CompositeKeyedObjectPoolFactory.
* @throws CloneNotSupportedException if a subclass calls this.
*/
public Object clone() throws CloneNotSupportedException {
if (!getClass().equals(CompositeKeyedObjectPoolFactory.class)) {
throw new CloneNotSupportedException("Subclasses must not call super.clone()");
}
// factory will be cloned in the constuctor
return new CompositeKeyedObjectPoolFactory(factory);
}
} java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPool.java 0000644 0000765 0000765 00000035404 10373424401 030403 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* An object pool who's behavior and functionality is determined by composition.
*
* Instances of this class should only be instantiated by {@link CompositeObjectPoolFactory} or other package-local * classes that are intimately familiar with it's proper usage.
* *Composit object pools are divided into three parts.
* *{@link Lender}: a lender's sole responsibilty is to maintain idle objects. A lender will never touch an object * that is considered to be active with the possible exception of an idle object being validated for possible eviction. *
* *{@link Manager}: a manager does most of the heavy lifting between a {@link Lender} and a {@link Tracker}. A * manager is responsible for activating and validating idle objects and passivating and possibly validating active * objects. It is also responsible for controling the growth and size of the pool.
* *{@link Tracker}: a tracker's sole responsibility is keeping track of active objects borrowed from the pool. A * tracker will never touch an object that is considered to be idle.
* * @see CompositeObjectPoolFactory * @author Sandy McArthur * @version $Revision$ $Date$ * @since #.# */ final class CompositeObjectPool implements ObjectPool, Cloneable, Serializable { private static final long serialVersionUID = -5874499972956918952L; /** * Factory used by this pool. */ // XXX: Add better handling of when this instance is not Serializable private final PoolableObjectFactory factory; /** * The collection of idle pooled objects. */ private final transient List pool; /** * Maintains idle objects and the order in which objects are borrowed. */ private final Lender lender; /** * Manages object transitions and controls the growth of the pool. */ private final Manager manager; /** * Tracks active objects. */ private final Tracker tracker; /** * Should returning objects be validated. */ private final boolean validateOnReturn; /** * Is this object pool still open. */ private volatile boolean open = true; /** * The configuration of the {@link CompositeObjectPoolFactory} that created this instance. This is needed for * cloning and helps {@link #toString()} be more friendly. */ private final CompositeObjectPoolFactory.FactoryConfig factoryConfig; CompositeObjectPool(final PoolableObjectFactory factory, final Manager manager, final Lender lender, final Tracker tracker, final boolean validateOnReturn) { this(factory, manager, lender, tracker, validateOnReturn, null); } CompositeObjectPool(final PoolableObjectFactory factory, final Manager manager, final Lender lender, final Tracker tracker, final boolean validateOnReturn, final CompositeObjectPoolFactory.FactoryConfig factoryConfig) { this(factory, new LinkedList(), manager, lender, tracker, validateOnReturn, factoryConfig); } CompositeObjectPool(final PoolableObjectFactory factory, final List pool, final Manager manager, final Lender lender, final Tracker tracker, final boolean validateOnReturn, final CompositeObjectPoolFactory.FactoryConfig factoryConfig) { if (factory == null) { throw new IllegalArgumentException("factory cannot be null."); } if (pool == null) { throw new IllegalArgumentException("pool cannot be null."); } if (manager == null) { throw new IllegalArgumentException("manager cannot be null."); } if (lender == null) { throw new IllegalArgumentException("lender cannot be null."); } if (tracker == null) { throw new IllegalArgumentException("tracker cannot be null."); } this.factory = factory; this.pool = pool; this.manager = manager; this.lender = lender; this.tracker = tracker; this.validateOnReturn = validateOnReturn; this.factoryConfig = factoryConfig; updateCompositeObjectPools(); } /** * Provide {@link Manager}s and {@link Lender}s with a reference back to this {@link CompositeObjectPool} if needed. */ private void updateCompositeObjectPools() { lender.setCompositeObjectPool(this); manager.setCompositeObjectPool(this); } /** * The order in which objects are borrowed. * * @return order in which objects are borrowed. */ Lender getLender() { return lender; } /** * Factory used by this pool. * * @return factory used by this pool. */ PoolableObjectFactory getFactory() { return factory; } /** * The collection of idle pooled objects. * * @return collection of idle pooled objects. */ List getPool() { return pool; } /** * Create an object using my {@link #setFactory factory} or other * implementation dependent mechanism, and place it into the pool. * addObject() is useful for "pre-loading" a pool with idle objects. * (Optional operation). * * @throws Exception if there is an unexpected problem. */ public void addObject() throws Exception { assertOpen(); synchronized (pool) { final Object obj = factory.makeObject(); tracker.borrowed(obj); // pretend it was borrowed so it can be returned. returnObject(obj); } } /** * Obtain an instance from my pool. * By contract, clients MUST return * the borrowed instance using * {@link #returnObject(Object) returnObject} * or a related method as defined in an implementation * or sub-interface. * * The behaviour of this method when the pool has been exhausted * is not specified (although it may be specified by implementations). * * @return an instance from my pool. * @throws Exception if there is an unexpected problem. */ public Object borrowObject() throws Exception { assertOpen(); return borrowObjectPrivately(); } /** * Basicly just the {@link #borrowObject()} method that doesn't check if the pool has been {@link #close() closed}. * Needed by {@link #clear()}. * * @return an instance from my pool. * @throws Exception if there is an unexpected problem. * @see #borrowObject() */ private Object borrowObjectPrivately() throws Exception { final Object obj; synchronized (pool) { obj = manager.nextFromPool(); // Must be synced else getNumActive() could be wrong in WaitLimitManager tracker.borrowed(obj); } return obj; } /** * Return an instance to my pool. * By contract, obj MUST have been obtained * using {@link #borrowObject() borrowObject} * or a related method as defined in an implementation * or sub-interface. * * @param obj a {@link #borrowObject borrowed} instance to be returned. * @throws Exception if there is an unexpected problem. */ public void returnObject(final Object obj) throws Exception { if (validateOnReturn) { if (!factory.validateObject(obj)) { invalidateObject(obj); return; } } try { factory.passivateObject(obj); } catch (Exception e) { invalidateObject(obj); return; } synchronized (pool) { tracker.returned(obj); // if the pool is closed, discard returned objects if (isOpen()) { manager.returnToPool(obj); } } } /** * Invalidates an object from the pool * By contract, obj MUST have been obtained * using {@link #borrowObject() borrowObject} * or a related method as defined in an implementation * or sub-interface. * * This method should be used when an object that has been borrowed * is determined (due to an exception or other problem) to be invalid. * If the connection should be validated before or after borrowing, * then the {@link PoolableObjectFactory#validateObject} method should be * used instead. * * @param obj a {@link #borrowObject borrowed} instance to be returned. * @throws Exception if there is an unexpected problem. */ public void invalidateObject(final Object obj) throws Exception { synchronized (pool) { if (pool.contains(obj)) { throw new IllegalStateException("An object currently in the pool cannot be invalidated."); } tracker.returned(obj); try { factory.destroyObject(obj); } catch (Exception e) { // ignored } finally { pool.notifyAll(); // tell any wait managers to try again. } } } /** * Clears any objects sitting idle in the pool, releasing any * associated resources (optional operation). * * @throws UnsupportedOperationException if this implementation does not support the operation * @throws Exception if there is an unexpected problem. */ public void clear() throws Exception, UnsupportedOperationException { synchronized (pool) { while (pool.size() > 0) { final Object obj = borrowObjectPrivately(); invalidateObject(obj); } if (pool instanceof ArrayList) { ((ArrayList)pool).trimToSize(); } } } /** * Close this pool, and free any resources associated with it. * * @throws Exception if there is an unexpected problem. */ public void close() throws Exception { open = false; Thread.yield(); // encourage any threads currently executing in the pool to finish first. synchronized (pool) { clear(); pool.notifyAll(); // Tell any WaitLimitManagers currently blocking to exit } } /** * Sets the {@link PoolableObjectFactory factory} I use * to create new instances (optional operation). * * @param factory the {@link PoolableObjectFactory} I use to create new instances. * @throws IllegalStateException when the factory cannot be set at this time * @throws UnsupportedOperationException if this implementation does not support the operation */ public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { throw new UnsupportedOperationException("Replacing the factory not supported. Create a new pool instance instead."); } /** * Return the number of instances * currently borrowed from my pool * (optional operation). * * @return the number of instances currently borrowed in my pool * @throws UnsupportedOperationException if this implementation does not support the operation */ public int getNumActive() throws UnsupportedOperationException { return tracker.getBorrowed(); } /** * Return the number of instances * currently idle in my pool (optional operation). * This may be considered an approximation of the number * of objects that can be {@link #borrowObject borrowed} * without creating any new instances. * * @return the number of instances currently idle in my pool * @throws UnsupportedOperationException if this implementation does not support the operation */ public int getNumIdle() throws UnsupportedOperationException { return lender.size(); } /** * Is this pool still open. * This is needed by the {@link WaitLimitManager} so it can terminate when the pool is {@link #close() closed}. * @returnfalse
if this pool has been closed.
*/
boolean isOpen() {
return open;
}
/**
* Throws an {@link IllegalStateException} when the pool has been closed.
* This should not be called by methods that are for returning objects to the pool.
* It's better to silently discard those objects over interupting program flow.
*
* @throws IllegalStateException when the pool has been closed.
*/
private void assertOpen() throws IllegalStateException {
if (!isOpen()) {
throw new IllegalStateException("pool has been closed.");
}
}
public String toString() {
final StringBuffer sb = new StringBuffer(128);
sb.append("CompositeObjectPool{");
if (factoryConfig != null) {
sb.append(factoryConfig);
} else {
sb.append("factory=").append(factory);
sb.append(", lender=").append(lender);
sb.append(", manager=").append(manager);
sb.append(", tracker=").append(tracker);
sb.append(", validateOnReturn=").append(validateOnReturn);
}
sb.append(", open=").append(open);
try {
final int numActive = getNumActive();
sb.append(", activeObjects=").append(numActive);
} catch (Exception e) {
// ignored
}
try {
final int numIdle = getNumIdle();
sb.append(", idleObjects=").append(numIdle);
} catch (Exception e) {
// ignored
}
sb.append('}');
return sb.toString();
}
/**
* Create a new pool with the same settings. Active or Idle objects are not shared with the new pool.
*
* @return a new {@link CompositeObjectPool} with the same configuration.
* @throws CloneNotSupportedException when this pool was contstucted without a factoryConfig.
*/
public Object clone() throws CloneNotSupportedException {
if (factoryConfig == null) {
throw new CloneNotSupportedException("Cloning not supported without a factoryConfig.");
}
return CompositeObjectPoolFactory.createPool(factoryConfig);
}
} java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPoolFactory.java 0000644 0000765 0000765 00000076555 10373432430 031750 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.ObjectPoolFactory;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* {@link ObjectPoolFactory} that builds a custom {@link ObjectPool} via composition.
*
* Default values for a newly created factory: *
Example usages:
* *To create a "stack" {@link ObjectPool} that keeps at most 5 idle objects, checks idle objects every 5 minutes to * see if they are still {@link PoolableObjectFactory#validateObject(Object) valid} and evicts invalid idle objects, * evicts idle objects after an hour regardless of wether or not they are * {@link PoolableObjectFactory#validateObject(Object) valid}, and throws an {@link IllegalStateException} when you * return an object that wasn't originally borrowed from the pool. *
*
* PoolableObjectFactory pof = ...; * CompositeObjectPoolFactory copf = new CompositeObjectPoolFactory(pof); * copf.setBorrowType(BorrowType.LIFO) * copf.setMaxIdle(5); * copf.setEvictInvalidFrequencyMillis(5 * 60 * 1000); * copf.setEvictIdleMillis(60 * 60 * 1000); * copf.setTrackingType(TrackingType.REFERENCE); * ObjectPool pool = copf.createPool(); ** *
To create a fifo {@link ObjectPool} that does not automatically create new objects as needed, allows * only 2 objects to be borrowed at a time, waits up to 10 seconds for an idle object to become available, * and populates a created pool with 3 objects. *
*
* PoolableObjectFactory pof = ...; * CompositeObjectPoolFactory copf = new CompositeObjectPoolFactory(pof); * copf.setsetExhaustionBehavior(ExhaustionBehavior.FAIL); * copf.setMaxActive(2); * copf.setLimitBehavior(LimitBehavior.WAIT); * copf.setMaxWaitMillis(10 * 1000); * ObjectPool pool = copf.createPool(); * pool.addObject(); pool.addObject(); pool.addObject(); ** *
To create a fifo {@link ObjectPool} that doesn't prevent idle objects from being garabage collected, detects when * borrowed objects are not returned to the pool and prints a stack trace from where they were borrowed. *
** PoolableObjectFactory pof = ...; * CompositeObjectPoolFactory copf = new CompositeObjectPoolFactory(pof); * copf.setBorrowType(BorrowType.SOFT_FIFO); * copf.setTrackingType(TrackingType.DEBUG); * ObjectPool pool = copf.createPool(); ** *
{@link ObjectPool}s created by this factory have the following properties: *
config
.
*
* @param config the settings to use to construct said pool.
* @return a new {@link ObjectPool}
*/
static ObjectPool createPool(final FactoryConfig config) {
if (config == null) {
throw new IllegalArgumentException("config must not be null.");
}
return new CompositeObjectPool(config.factory, getList(config), getManager(config), getLender(config),
getTracker(config), config.validateOnReturn, config);
}
/**
* Choose a {@link List} implementation optimized for this pool's behavior.
*
* @param config
* @return a {@link List} implementation optimized for this pool's behavior.
*/
private static List getList(final FactoryConfig config) {
final List list; // LIFO is more suited to an ArrayList, FIFO is more suited to a LinkedList
if (BorrowType.NULL.equals(config.borrowType) || config.maxIdle == 0) {
// an empty pool can use an empty list.
list = Collections.EMPTY_LIST;
} else if (BorrowType.LIFO.equals(config.borrowType) || BorrowType.SOFT_LIFO.equals(config.borrowType)) {
// pre-allocate the backing array if the max size is known.
if (config.maxIdle >= 0) {
list = new ArrayList(config.maxIdle);
} else {
list = new ArrayList();
}
} else {
// For small list sizes the cost of shuffling the items in an array down one spot
// is cheaper than for LinkList to manage it's internal stuctures.
// The threshold (10) was based on some benchmarks on some 1.4 and 1.5 JVMs was between 10 to 25
if (0 <= config.maxIdle && config.maxIdle <= 10) {
list = new ArrayList(config.maxIdle);
} else {
list = new LinkedList();
}
}
return list;
}
/**
* Choose a {@link Lender} based on this factory's settings.
*
* @return a new lender for an object pool.
* @param config
*/
private static Lender getLender(final FactoryConfig config) {
final BorrowType borrowType = config.borrowType;
Lender lender;
if (config.maxIdle != 0) {
if (BorrowType.FIFO.equals(borrowType)) {
lender = new FifoLender();
} else if (BorrowType.LIFO.equals(borrowType)) {
lender = new LifoLender();
} else if (BorrowType.SOFT_FIFO.equals(borrowType)) {
lender = new SoftLender(new FifoLender());
} else if (BorrowType.SOFT_LIFO.equals(borrowType)) {
lender = new SoftLender(new LifoLender());
} else if (BorrowType.NULL.equals(borrowType)) {
lender = new NullLender();
} else {
throw new IllegalStateException("No clue what this borrow type is: " + borrowType);
}
} else {
lender = new NullLender();
}
// If the lender is a NullLender then there is no point to evicting idle objects that aren't there.
if (!(lender instanceof NullLender)) {
// If the evictIdleMillis were less than evictInvalidFrequencyMillis
// then the InvalidEvictorLender would never run.
if (config.evictInvalidFrequencyMillis > 0 && config.evictIdleMillis > config.evictInvalidFrequencyMillis) {
lender = new InvalidEvictorLender(lender);
((InvalidEvictorLender)lender).setValidationFrequencyMillis(config.evictInvalidFrequencyMillis);
}
if (config.evictIdleMillis > 0) {
lender = new IdleEvictorLender(lender);
((IdleEvictorLender)lender).setIdleTimeoutMillis(config.evictIdleMillis);
}
}
return lender;
}
/**
* Compose a {@link Manager} based on this factory's settings.
*
* @param config
* @return a new manager for an object pool.
*/
private static Manager getManager(final FactoryConfig config) {
Manager manager;
final ExhaustionBehavior exhaustionBehavior = config.exhaustionBehavior;
if (ExhaustionBehavior.GROW.equals(exhaustionBehavior)) {
manager = new GrowManager();
} else if (ExhaustionBehavior.FAIL.equals(exhaustionBehavior)) {
if (BorrowType.NULL.equals(config.borrowType)) {
throw new IllegalStateException("Using the NULL borrow type with the FAIL exhaustion behavior is pointless.");
} else if (config.maxIdle == 0) {
throw new IllegalStateException("Using the FAIL exhaustion behavior with a max of zero idle objects is pointless.");
}
manager = new FailManager();
} else {
throw new IllegalStateException("No clue what this exhaustion behavior is: " + exhaustionBehavior);
}
final int maxActive = config.maxActive;
if (maxActive > 0) {
if (TrackingType.NULL.equals(config.trackerType)) {
throw new IllegalStateException("Using the NULL tracker and limiting pool size is not valid.");
}
final LimitBehavior limitBehavior = config.limitBehavior;
if (LimitBehavior.FAIL.equals(limitBehavior)) {
manager = new FailLimitManager(manager);
} else if (LimitBehavior.WAIT.equals(limitBehavior)) {
manager = new WaitLimitManager(manager);
((WaitLimitManager)manager).setMaxWaitMillis(config.maxWaitMillis);
} else {
throw new IllegalStateException("No clue what this wait behavior is: " + limitBehavior);
}
((ActiveLimitManager)manager).setMaxActive(maxActive);
}
if (config.maxIdle > 0) {
manager = new IdleLimitManager(manager);
((IdleLimitManager)manager).setMaxIdle(config.maxIdle);
}
return manager;
}
/**
* Choose a {@link Tracker} based on this factory's settings.
*
* @param config
* @return a new tracker for an object pool.
*/
private static Tracker getTracker(final FactoryConfig config) {
final Tracker tracker;
final TrackingType trackerType = config.trackerType;
if (TrackingType.SIMPLE.equals(trackerType)) {
tracker = new SimpleTracker();
} else if (TrackingType.NULL.equals(trackerType)) {
tracker = new NullTracker();
} else if (TrackingType.REFERENCE.equals(trackerType)) {
tracker = new ReferenceTracker();
} else if (TrackingType.DEBUG.equals(trackerType)) {
tracker = new DebugTracker();
} else {
throw new IllegalStateException("No clue what this tracking type is: " + trackerType);
}
return tracker;
}
/**
* Create or use a cached {@link FactoryConfig} with the factory's current settings.
*
* @return this factory's current settings in a "struct".
*/
private FactoryConfig getConfig() {
synchronized (lock) {
if (config == null) {
config = new FactoryConfig(this);
}
return config;
}
}
/**
* Object factory used by pools created from this factory.
*
* @return object factory used by pools created from this factory.
*/
public PoolableObjectFactory getFactory() {
return factory;
}
/**
* Set the object factory used by pools created from this factory.
*
* @param factory the object factory to be used by pools.
* @throws IllegalArgumentException if factory
is null
.
*/
public void setFactory(final PoolableObjectFactory factory) throws IllegalArgumentException {
if (factory == null) {
throw new IllegalArgumentException("object factory must not be null.");
}
synchronized (lock){
config = null;
this.factory = factory;
}
}
/**
* Order in which objects are borrowed from the pool.
*
* @return the order in which objects are pooled.
*/
public BorrowType getBorrowType() {
return borrowType;
}
/**
* Set the order in which objects are borrowed from the pool.
*
* Note: this doesn't mean much if {@link #setMaxIdle(int) maxIdle} is set to zero.
* * @param borrowType the order in which objects are pooled. * @throws IllegalArgumentException whenborrowType
is null
.
*/
public void setBorrowType(final BorrowType borrowType) throws IllegalArgumentException {
if (borrowType == null) {
throw new IllegalArgumentException("borrow type must not be null.");
}
synchronized (lock){
config = null;
this.borrowType = borrowType;
}
}
/**
* Behavior of the pool when all idle objects have been exhasted.
*
* @return behavior of the pool when all idle objects have been exhasted.
*/
public ExhaustionBehavior getExhaustionBehavior() {
return exhaustionBehavior;
}
/**
* Set the behavior for when the pool is exhausted of any idle objects.
*
* @param exhaustionBehavior the desired exhausted behavior of the pool.
* @throws IllegalArgumentException when exhaustionBehavior
is null
.
*/
public void setExhaustionBehavior(final ExhaustionBehavior exhaustionBehavior) throws IllegalArgumentException {
if (exhaustionBehavior == null) {
throw new IllegalArgumentException("exhaustion behavior must not be null.");
}
synchronized (lock){
config = null;
this.exhaustionBehavior = exhaustionBehavior;
}
}
/**
* Maximum number of idle objects in the pool.
* A negative value means unlimited.
* Zero means the pool will behave like a factory.
* A positve value limits the number of idle objects.
*
* @return a non-negative value is the maximum number of idle objects in the pool, else unlimited.
*/
public int getMaxIdle() {
return maxIdle;
}
/**
* Set the maximum number of idle objects in the pool.
* A negative value means unlimited.
* Zero means the pool will behave like a factory.
* A positve value limits the number of idle objects.
*
* @param maxIdle a non-negative value is the maximum number of idle objects in the pool, else unlimited.
*/
public void setMaxIdle(final int maxIdle) {
synchronized (lock){
config = null;
this.maxIdle = maxIdle;
}
}
/**
* Maximum number of objects associated with this pool. A non-positive value means there is no limit.
*
* @return if > 0 the the maximum number of objects else no size limit.
*/
public int getMaxActive() {
return maxActive;
}
/**
* Set the maximum objects associated with this pool. Any non-positive value means there is no limit.
*
* @param maxActive the limit of active and idle objects in the pool or <= 0 for no limit.
*/
public void setMaxActive(final int maxActive) {
synchronized (lock){
config = null;
this.maxActive = maxActive;
}
}
/**
* Behavior of the pool when the limit of active objects has been reached.
*
* @return the behavior of the pool when the limit of active objects has been reached.
* @see #getMaxWaitMillis()
*/
public LimitBehavior getLimitBehavior() {
return limitBehavior;
}
/**
* Set the behavior of when the pool's limit of active objects has been reached.
*
* @param limitBehavior action to take if the pool has an object limit and is exhausted.
* @throws IllegalArgumentException when limitBehavior
is null
.
* @see #setMaxWaitMillis(int)
*/
public void setLimitBehavior(final LimitBehavior limitBehavior) throws IllegalArgumentException {
if (limitBehavior == null) {
throw new IllegalArgumentException("limit behavior must not be null.");
}
synchronized (lock){
config = null;
this.limitBehavior = limitBehavior;
}
}
/**
* Wait time in milli-seconds for an object to become available to the pool when the {@link LimitBehavior#WAIT WAIT}
* {@link #setLimitBehavior(LimitBehavior) limit behavior} is used.
*
* @return the wait time for an object to become available to the pool.
* @see #getLimitBehavior()
*/
public int getMaxWaitMillis() {
return maxWaitMillis;
}
/**
* Set the wait time in milli-seconds for an object to become available to the pool when it was exhausted.
* This has no effect unless the {@link #setLimitBehavior(LimitBehavior) limit behavior}
* is set to {@link LimitBehavior#WAIT}.
*
* @param maxWaitMillis the milli-seconds to wait for an available object in the pool or <= 0 for no limit.
* @see #setLimitBehavior(LimitBehavior)
*/
public void setMaxWaitMillis(final int maxWaitMillis) {
synchronized (lock){
config = null;
this.maxWaitMillis = maxWaitMillis;
}
}
/**
* Type of tracking for active objects while they are borrowed from the pool.
*
* @return Type of tracking for active objects while they are borrowed from the pool.
*/
public TrackingType getTrackerType() {
return trackerType;
}
/**
* Set the type of tracking for active objects while they are borrowed from the pool.
*
* @param trackerType type of tracking for active objects.
* @throws IllegalArgumentException when trackerType
is null
.
*/
public void setTrackerType(final TrackingType trackerType) throws IllegalArgumentException {
if (trackerType == null) {
throw new IllegalArgumentException("tracker type must not be null.");
}
synchronized (lock){
config = null;
this.trackerType = trackerType;
}
}
/**
* Are objects validated when they are returned to the pool.
*
* @return are objects validated when they are returned to the pool.
*/
public boolean isValidateOnReturn() {
return validateOnReturn;
}
/**
* Set if objects should be validated when returned to the pool.
*
* @param validateOnReturn true
to validate objects when they are added to the pool.
*/
public void setValidateOnReturn(final boolean validateOnReturn) {
synchronized (lock){
config = null;
this.validateOnReturn = validateOnReturn;
}
}
/**
* Idle timeout for idle objects to be evicted.
* A non-positive value means do not evict objects just because they are idle.
*
* @return if positive the time in milli-seconds to evict idle objects.
*/
public long getEvictIdleMillis() {
synchronized (lock) {
return evictIdleMillis;
}
}
/**
* Set the idle timeout for idle objects to be evicted.
* A non-positive value means do not evict objects just because they are idle.
*
* @param evictIdleMillis if positive the time in milli-seconds to evict idle objects.
*/
public void setEvictIdleMillis(final long evictIdleMillis) {
synchronized (lock){
config = null;
this.evictIdleMillis = evictIdleMillis;
}
}
/**
* Frequency idle objects should be checked to be still valid.
* A non-positive value means do not evict objects just because they fail to validate.
*
* @return if positive the frequency in milli-seconds to check that idle objects are still valid.
*/
public long getEvictInvalidFrequencyMillis() {
synchronized (lock) {
return evictInvalidFrequencyMillis;
}
}
/**
* Set the frequency idle objects should be checked to be still valid.
* A non-positive value means do not evict objects just because they fail to validate.
*
* @param evictInvalidFrequencyMillis if positive the frequency in milli-seconds to check that
* idle objects are still valid.
*/
public void setEvictInvalidFrequencyMillis(final long evictInvalidFrequencyMillis) {
synchronized (lock){
config = null;
this.evictInvalidFrequencyMillis = evictInvalidFrequencyMillis;
}
}
/**
* Create a copy of this factory with the existing values.
* @return a copy of this {@link ObjectPoolFactory}.
* @throws CloneNotSupportedException if {@link Object#clone()} does.
*/
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("CompositeObjectPoolFactory{");
sb.append(getConfig());
sb.append('}');
return sb.toString();
}
/**
* A "struct" to capture this factory's settings so {@link CompositeObjectPool}s can print friendly
* {@link Object#toString()} messages and be {@link Object#clone()}. For the meaning of each field see
* the field of {@link CompositeObjectPoolFactory} with the same name.
*/
static final class FactoryConfig implements Serializable {
private static final long serialVersionUID = 8055395905602482612L;
/** @see CompositeObjectPoolFactory#factory */
// XXX: Add better handling of when this instance is not Serializable
private final PoolableObjectFactory factory;
/** @see CompositeObjectPoolFactory#borrowType */
private final BorrowType borrowType;
/** @see CompositeObjectPoolFactory#exhaustionBehavior */
private final ExhaustionBehavior exhaustionBehavior;
/** @see CompositeObjectPoolFactory#maxIdle */
private final int maxIdle;
/** @see CompositeObjectPoolFactory#maxActive */
private final int maxActive;
/** @see CompositeObjectPoolFactory#limitBehavior */
private final LimitBehavior limitBehavior;
/** @see CompositeObjectPoolFactory#maxWaitMillis */
private final int maxWaitMillis;
/** @see CompositeObjectPoolFactory#trackerType */
private final TrackingType trackerType;
/** @see CompositeObjectPoolFactory#validateOnReturn */
private final boolean validateOnReturn;
/** @see CompositeObjectPoolFactory#evictIdleMillis */
private final long evictIdleMillis;
/** @see CompositeObjectPoolFactory#evictInvalidFrequencyMillis */
private final long evictInvalidFrequencyMillis;
/**
* Convenience constuctor. This must be called from a synchronized context to be thread-safe.
*/
FactoryConfig(final CompositeObjectPoolFactory copf) {
this(copf.getFactory(), copf.getBorrowType(), copf.getExhaustionBehavior(), copf.getMaxIdle(),
copf.getMaxActive(), copf.getLimitBehavior(), copf.getMaxWaitMillis(), copf.getTrackerType(),
copf.isValidateOnReturn(), copf.getEvictIdleMillis(), copf.getEvictInvalidFrequencyMillis());
}
FactoryConfig(final PoolableObjectFactory factory, final BorrowType borrowType,
final ExhaustionBehavior exhaustionBehavior, final int maxIdle, final int maxActive,
final LimitBehavior limitBehavior, final int maxWaitMillis, final TrackingType trackerType,
final boolean validateOnReturn, final long evictIdleMillis,
final long evictInvalidFrequencyMillis) {
this.factory = factory;
this.borrowType = borrowType;
this.exhaustionBehavior = exhaustionBehavior;
this.maxIdle = maxIdle;
this.maxActive = maxActive;
this.limitBehavior = limitBehavior;
this.maxWaitMillis = maxWaitMillis;
this.trackerType = trackerType;
this.validateOnReturn = validateOnReturn;
this.evictIdleMillis = evictIdleMillis;
this.evictInvalidFrequencyMillis = evictInvalidFrequencyMillis;
}
public String toString() {
final StringBuffer sb = new StringBuffer();
sb.append("factory=").append(factory);
sb.append(", borrowType=").append(borrowType);
sb.append(", exhaustionBehavior=").append(exhaustionBehavior);
sb.append(", maxIdle=").append(maxIdle);
sb.append(", maxActive=").append(maxActive);
if (maxActive > 0) {
sb.append(", limitBehavior=").append(limitBehavior);
if (LimitBehavior.WAIT.equals(limitBehavior)) {
sb.append(", maxWaitMillis=").append(maxWaitMillis);
}
}
sb.append(", trackerType=").append(trackerType);
sb.append(", validateOnReturn=").append(validateOnReturn);
if (evictIdleMillis > 0) {
sb.append(", evictIdleMillis=").append(evictIdleMillis);
}
if (evictInvalidFrequencyMillis > 0) {
sb.append(", evictInvalidFrequencyMillis=").append(evictInvalidFrequencyMillis);
}
return sb.toString();
}
}
} java/org/mcarthur/sandy/commons/pool/composite/DebugTracker.java 0000644 0000765 0000765 00000007627 10373454623 027041 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Keeps track of active objects with {@link Reference}s and logs when they are not returned to the pool.
*
* @see TrackingType#DEBUG
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class DebugTracker extends ReferenceTracker implements Serializable {
private static final long serialVersionUID = -5536120104213707789L;
/**
* Logger for lost objects.
*/
private static final Logger LOGGER = Logger.getLogger(DebugTracker.class.getName());
/**
* Message for logger.
*/
private static final String LOG_MESSAGE = "Borrowed object was not returned to the pool.";
/**
* Wrap the object in a reference that records the stack.
*
* @param obj the object to be wrapped.
* @return a {@link StackWeakReference} around obj.
*/
protected IdentityReference wrapBorrowed(final Object obj) {
return new StackWeakReference(obj, rq);
}
/**
* Log that an object was lost.
*
* @param ref the reference to the lost former object.
*/
protected void referenceToBeRemoved(final IdentityReference ref) {
LOGGER.log(Level.WARNING, LOG_MESSAGE, ((StackWeakReference)ref).getStack());
}
public String toString() {
return "DebugTracker{" +
"active=" + map.size() +
", lost=" + getLost() +
"}";
}
/**
* A {@link WeakReference} that keeps track of the stack trace from when the reference was created.
*/
private static final class StackWeakReference extends WeakReference implements IdentityReference {
/**
* The message for the {@link Throwable} that was used to capture a stack trace.
*/
private static final String THROWABLE_MESSAGE = "Stack trace at time of borrow for: ";
/**
* The {@link System#identityHashCode(Object)} of the object.
*/
private final int ident; // XXX: Going need something more than this on 64 bit systems.
/**
* The {@link Throwable} caputing the stack trace.
*/
private final Throwable stack;
/**
* Calculate a key for referent
and record the current stack.
* @param referent object the new weak reference will refer to
* @param q queue the weak reference is registered with
* @see WeakReference#WeakReference(Object, ReferenceQueue)
*/
StackWeakReference(final Object referent, final ReferenceQueue q) {
super(referent, q);
ident = System.identityHashCode(referent);
// Once JSK 1.5 is a requirement of pool it may be worth using 1.5's Thread.getStackTrace()
stack = new Throwable(THROWABLE_MESSAGE + referent);
}
public IdentityKey getKey() {
return new IdentityKey(ident);
}
/**
* The {@link Throwable} that captured the stack trace.
*
* @return the captured the stack trace.
*/
public Throwable getStack() {
return stack;
}
}
} java/org/mcarthur/sandy/commons/pool/composite/DelegateLender.java 0000644 0000765 0000765 00000006200 10373450630 027317 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.util.ListIterator;
/**
* Delegates all work to another lender. Subclasses should call super.method(...)
to access the delegates.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
abstract class DelegateLender extends AbstractLender implements Serializable {
private static final long serialVersionUID = -4403177642421760774L;
/**
* The delegate lender. This is only accessed by subclasses by calling super.method(...).
*/
private final Lender delegate;
/**
* Create a lender that delegates some behavior to another lender.
*
* @param delegate the lender to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
protected DelegateLender(final Lender delegate) throws IllegalArgumentException {
if (delegate == null) {
throw new IllegalArgumentException("delegate Lender must not be null.");
}
this.delegate = delegate;
}
/**
* Calls {@link AbstractLender#setCompositeObjectPool(CompositeObjectPool)} and the delegate's
* {@link Lender#setCompositeObjectPool(CompositeObjectPool)} methods.
*
* @param objectPool the pool to associate with.
*/
public void setCompositeObjectPool(final CompositeObjectPool objectPool) throws IllegalArgumentException, IllegalStateException {
super.setCompositeObjectPool(objectPool);
delegate.setCompositeObjectPool(getObjectPool());
}
/**
* Calls the delegate's {@link Lender#borrow()} method.
*
* @return a previously idle object.
*/
public Object borrow() {
return delegate.borrow();
}
/**
* Calls the delegate's {@link Lender#repay(Object)} method.
*
* @param obj the object to return to the idle object pool.
*/
public void repay(final Object obj) {
delegate.repay(obj);
}
/**
* Calls the delegate's {@link Lender#listIterator()} method.
*
* @return a list iterator of the elements in this pool.
*/
public ListIterator listIterator() {
return delegate.listIterator();
}
/**
* Calls the delegate's {@link Lender#size()} method.
*
* @return the size of the idle object pool the lender is accessing.
*/
public int size() {
return delegate.size();
}
public String toString() {
return delegate.toString();
}
} java/org/mcarthur/sandy/commons/pool/composite/DelegateManager.java 0000644 0000765 0000765 00000006366 10373432123 027472 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* Delegates all work to another manager. Subclasses should call super.method(...)
to access the delegates.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
abstract class DelegateManager extends AbstractManager implements Serializable {
private static final long serialVersionUID = -8516695099130531284L;
/**
* The manager that actually handles the interaction with the pool.
* This is only accessed by subclasses by calling super.method(...).
*/
private final Manager delegate;
/**
* Create a manager that delegates some behavior to another manager.
*
* @param delegate the manager to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
protected DelegateManager(final Manager delegate) throws IllegalArgumentException {
if (delegate == null) {
throw new IllegalArgumentException("delegate must not be null.");
}
this.delegate = delegate;
}
/**
* Called once to associate this limit manager with an object pool by the {@link CompositeObjectPool} constructor.
* This also sets the {@link Manager#setCompositeObjectPool(CompositeObjectPool)} for the {@link #delegate}.
*
* @param objectPool the pool to associate with.
* @throws IllegalArgumentException if objectPool
is null
.
* @throws IllegalStateException if this method is called more than once.
*/
public void setCompositeObjectPool(final CompositeObjectPool objectPool) {
super.setCompositeObjectPool(objectPool);
delegate.setCompositeObjectPool(objectPool);
}
/**
* Delegates to another {@link Manager}.
*
* @return a new or activated object.
* @throws NoSuchElementException if the pool is empty and no new object can be created.
* @throws Exception usually from {@link PoolableObjectFactory} methods.
*/
public Object nextFromPool() throws Exception {
return delegate.nextFromPool();
}
/**
* Delegates to another {@link Manager}.
*
* @param obj the object to return to the pool.
* @throws Exception as thrown by {@link PoolableObjectFactory#passivateObject(Object)}.
*/
public void returnToPool(final Object obj) throws Exception {
delegate.returnToPool(obj);
}
public String toString() {
return delegate.toString();
}
} java/org/mcarthur/sandy/commons/pool/composite/EvictorLender.java 0000644 0000765 0000765 00000015207 10373701401 027222 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.lang.ref.Reference;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Timer;
import java.util.TimerTask;
/**
* Base class for a {@link Lender} that evicts objects from the idle object pool.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
abstract class EvictorLender extends DelegateLender implements Serializable {
private static final long serialVersionUID = 4040627184050939757L;
/**
* Shared evictor timer used by all {@link EvictorLender}s.
*/
private static final Timer EVICTOR = new Timer(true);
/**
* If this evictor delegates to another evictor then don't bother pruning when {@link #size()} is called because the
* delegate will do that too.
*/
private final boolean prune;
/**
* Create a lender that may evict objects from the idle object pool.
*
* @param delegate delegate the lender to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
protected EvictorLender(final Lender delegate) throws IllegalArgumentException {
super(delegate);
prune = !(delegate instanceof EvictorLender);
}
/**
* Calls the delegate's {@link Lender#borrow()} method and unwrapps any {@link EvictorLender.EvictorReference}.
*
* @return a previously idle object.
*/
public Object borrow() {
final EvictorReference ref = (EvictorReference)super.borrow();
Object obj = null;
if (ref != null) {
obj = ref.get();
ref.clear();
}
return obj;
}
/**
* Calls the delegate's {@link Lender#repay(Object)} method.
* Calls {@link #createReference(Object)} to wrap the object.
*
* @param obj the object to return to the idle object pool.
*/
public void repay(final Object obj) {
super.repay(createReference(obj));
}
public ListIterator listIterator() {
return new EvictorListIterator(super.listIterator());
}
/**
* Return the size of the idle object pool. Also removes any broken {@link EvictorLender.EvictorReference}s so the
* size is more accurate.
*
* @return the size of the idle object pool the lender is accessing.
*/
public int size() {
if (prune) {
synchronized (getObjectPool().getPool()) {
final Iterator iter = super.listIterator();
while (iter.hasNext()) {
final EvictorReference ref = (EvictorReference)iter.next();
if (ref.get() == null) {
iter.remove();
}
}
}
}
return super.size();
}
/**
* Wrap an idle object in an {@link EvictorLender.EvictorReference} and schedule it's eviction with the
* {@link #getTimer() evictor timer}. {@link TimerTask}s used by the evictor timer must synchronize on the
* {@link CompositeObjectPool#getPool() idle object pool} to be thread-safe.
*
* @param obj idle object to be wrapped in an {@link EvictorLender.EvictorReference}.
* @return the wrapped idle object.
*/
protected abstract EvictorReference createReference(Object obj);
/**
* Get the {@link Timer} used for eviction by this {@link EvictorLender}.
*
* @return the {@link Timer} used for evictions.
*/
protected final Timer getTimer() {
// Future version may want to manage more than one TimerTask. For now one is fine.
return EVICTOR;
}
/**
* This is designed to mimick the {@link Reference} api.
* The only reason a {@link Reference} subclass isn't used is there is no "StrongReference" implementation.
*/
protected interface EvictorReference {
/**
* Returns this evictor reference's referent.
*
* @return The object to which this evictor reference refers,
* or null if this reference object has been cleared.
* @see Reference#get()
*/
public Object get();
/**
* Clears this reference.
*
* @see Reference#clear()
*/
public void clear();
}
/**
* A {@link ListIterator} that unwrapps {@link EvictorLender.EvictorReference}s.
*/
private static class EvictorListIterator implements ListIterator {
private final ListIterator iter;
private EvictorListIterator(final ListIterator iter) {
this.iter = iter;
}
public boolean hasNext() {
return iter.hasNext();
}
/**
* Unwrap an {@link EvictorLender.EvictorReference} and return the next object if it hasn't been evicted.
*
* @return an unwrapped object or null
if an object has been evicted.
* @see ListIterator#next()
*/
public Object next() {
final EvictorReference ref = (EvictorReference)iter.next();
return ref != null ? ref.get() : null;
}
public boolean hasPrevious() {
return iter.hasPrevious();
}
/**
* Unwrap an {@link EvictorLender.EvictorReference} and return the previous object if it hasn't been evicted.
*
* @return an unwrapped object or null
if an object has been evicted.
* @see ListIterator#previous()
*/
public Object previous() {
final EvictorReference ref = (EvictorReference)iter.previous();
return ref != null ? ref.get() : null;
}
public int nextIndex() {
return iter.nextIndex();
}
public int previousIndex() {
return iter.previousIndex();
}
public void remove() {
iter.remove();
}
public void set(final Object o) {
iter.set(o);
}
public void add(final Object o) {
iter.add(o);
}
}
} java/org/mcarthur/sandy/commons/pool/composite/ExhaustionBehavior.java 0000644 0000765 0000765 00000004377 10373003300 030263 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.ObjectPool;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* Specifies the behavor of the pool when the pool is out of idle objects.
*
* @see CompositeObjectPoolFactory#setExhaustionBehavior(ExhaustionBehavior)
* @see CompositeKeyedObjectPoolFactory#setExhaustionBehavior(ExhaustionBehavior)
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
public final class ExhaustionBehavior implements Serializable {
private static final long serialVersionUID = -4895490364329810018L;
/**
* Grow the pool when all idle objects have been exhausted.
*/
public static final ExhaustionBehavior GROW = new ExhaustionBehavior("GROW");
/**
* Throw a {@link NoSuchElementException} when all idle objects have been exhaused. Clients of the poll must
* call {@link ObjectPool#addObject()} to prefill the pool.
*/
public static final ExhaustionBehavior FAIL = new ExhaustionBehavior("FAIL");
/**
* enum name.
*/
private final String name;
private ExhaustionBehavior(final String name) {
this.name = name;
}
public String toString() {
return name;
}
// Autogenerated with Java 1.5 enums
public static ExhaustionBehavior[] values() {
return new ExhaustionBehavior[] {FAIL, GROW};
}
// necessary for serialization
private static int nextOrdinal = 0;
private final int ordinal = nextOrdinal++;
private Object readResolve() throws ObjectStreamException {
return values()[ordinal];
}
} java/org/mcarthur/sandy/commons/pool/composite/FailLimitManager.java 0000644 0000765 0000765 00000004772 10373435123 027634 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* Throws {@link NoSuchElementException} when the max number of active objects has been reached.
*
* @see LimitBehavior#FAIL
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class FailLimitManager extends ActiveLimitManager implements Serializable {
private static final long serialVersionUID = 4055528475643314990L;
/**
* Create a manager that when the limit of active objects has been reached throws a {@link NoSuchElementException}.
*
* @param delegate the manager to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
FailLimitManager(final Manager delegate) throws IllegalArgumentException {
super(delegate);
}
/**
* Checks to see how many total objects are in play and will not allow more than that.
* Delegates object management to another {@link Manager}.
*
* @return a new or activated object.
* @throws NoSuchElementException if the pool is empty and no new object can be created.
* @throws Exception usually from {@link PoolableObjectFactory} methods.
*/
public Object nextFromPool() throws NoSuchElementException, Exception {
if (objectPool.getNumActive() < getMaxActive()) {
return super.nextFromPool();
} else {
throw new NoSuchElementException("No more than " + getMaxActive() + " objects allowed from this pool. Currently " + objectPool.getNumActive() + " have been borrowed.");
}
}
public String toString() {
return "FailLimitManager{" +
"maxActive=" + getMaxActive() +
", delegate=" + super.toString() +
"}";
}
} java/org/mcarthur/sandy/commons/pool/composite/FailManager.java 0000644 0000765 0000765 00000011532 10373003300 026611 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* Throws a {@link NoSuchElementException} when the idle pool is exhausted. If you want to add objects to the pool you
* should call {@link ObjectPool#addObject()}.
*
* @see ExhaustionBehavior#FAIL
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class FailManager extends AbstractManager implements Serializable {
private static final long serialVersionUID = 2245468648709521897L;
/**
* Thread local to hold on to the first cause that prevented us from providing an object from the pool.
* This must be cleared else it will either leak memory or provide confusing results in future invocations of
* {@link #nextFromPool()}.
*/
private final transient ThreadLocal cause = new ThreadLocal();
/**
* Retreives the next object from the pool. Objects from the pool will be
* {@link PoolableObjectFactory#activateObject(Object) activated} and
* {@link PoolableObjectFactory#validateObject(Object) validated}.
* No objects will be {@link PoolableObjectFactory#makeObject() created}. Use {@link ObjectPool#addObject()} to
* populate the pool.
*
* @return a new or activated object.
* @throws NoSuchElementException if the pool is empty and no new object can be created.
* @throws Exception usually from {@link PoolableObjectFactory} methods.
*/
public Object nextFromPool() throws Exception {
assert Thread.holdsLock(objectPool.getPool());
Object obj = null;
// Drain until good or empty
while (objectPool.getLender().size() > 0 && obj == null) {
obj = objectPool.getLender().borrow();
if (obj != null) {
obj = activateOrDestroy(obj);
try {
if (obj != null && !objectPool.getFactory().validateObject(obj)) {
objectPool.invalidateObject(obj);
obj = null; // try again
}
} catch (Exception e1) {
updateCause(e1);
try {
objectPool.getFactory().destroyObject(obj);
} catch (Exception e2) {
// ignore
}
obj = null; // try again
}
}
}
if (obj == null) {
final Throwable t = (Throwable)cause.get();
final NoSuchElementException nsee = new NoSuchElementException("Pool configued to fail when exhausted.");
if (t != null) {
nsee.initCause(t);
cause.set(null); // clear reference
}
throw nsee;
}
cause.set(null); // clear reference
return obj;
}
/**
* {@link PoolableObjectFactory#activateObject(Object) Activate} an object or if that fails
* {@link PoolableObjectFactory#destroyObject(Object) destroy} it. If an exception is thrown it is saved to the
* {@link #cause} so that it can be part of the {@link NoSuchElementException} if this manager fails to get another
* object.
*
* @param obj the object to be activated or destroyed.
* @return the activated object or null if it was destroyed.
*/
private Object activateOrDestroy(final Object obj) {
try {
objectPool.getFactory().activateObject(obj);
} catch (Exception e1) {
updateCause(e1);
try {
objectPool.getFactory().destroyObject(obj);
} catch (Exception e2) {
updateCause(e2);
}
return null; // try again
}
return obj;
}
/**
* Set the {@link #cause} for failure if it hasn't been set yet.
*
* @param t the real {@link Throwable#initCause(Throwable) cause}.
*/
private void updateCause(final Throwable t) {
final Throwable previousCause = (Throwable)cause.get();
if (previousCause == null) {
cause.set(t);
}
}
public String toString() {
return "FailManager{}";
}
} java/org/mcarthur/sandy/commons/pool/composite/FifoLender.java 0000644 0000765 0000765 00000002562 10373450326 026501 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
/**
* A First In First Out (FIFO) {@link Lender}.
*
* @see BorrowType#FIFO
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class FifoLender extends AbstractLender implements Serializable {
private static final long serialVersionUID = 8586173154375349810L;
public Object borrow() {
final List pool = getObjectPool().getPool();
assert Thread.holdsLock(pool);
if (pool instanceof LinkedList) {
return ((LinkedList)pool).removeFirst();
} else {
return pool.remove(0);
}
}
public String toString() {
return "FIFO";
}
} java/org/mcarthur/sandy/commons/pool/composite/GrowManager.java 0000644 0000765 0000765 00000006300 10373444556 026677 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
/**
* Grows the pool automatically when it is exhausted.
* Whe the idle object pool is exhausted a new new object will be created via
* {@link PoolableObjectFactory#makeObject()}.
*
* @see ExhaustionBehavior#GROW
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class GrowManager extends AbstractManager implements Serializable {
private static final long serialVersionUID = 1225746308358794900L;
/**
* Retreives the next object from the pool, creating new objects if the pool has been exhausted.
*
* @return a new or activated object.
* @throws Exception when {@link PoolableObjectFactory#makeObject()} fails.
*/
public Object nextFromPool() throws Exception {
assert Thread.holdsLock(objectPool.getPool());
Object obj = null;
// Drain until good or empty
while (objectPool.getLender().size() > 0 && obj == null) {
obj = objectPool.getLender().borrow();
if (obj != null) {
obj = activateOrDestroy(obj);
try {
if (obj != null && !objectPool.getFactory().validateObject(obj)) {
objectPool.invalidateObject(obj);
obj = null; // try again
}
} catch (Exception e1) {
try {
objectPool.getFactory().destroyObject(obj);
} catch (Exception e2) {
// ignore
}
obj = null; // try again
}
}
}
if (obj == null) {
obj = objectPool.getFactory().makeObject();
}
return obj;
}
/**
* {@link PoolableObjectFactory#activateObject(Object) Activate} an object or if that fails
* {@link PoolableObjectFactory#destroyObject(Object) destroy} it.
*
* @param obj the object to be activated or destroyed.
* @return the activated object or null if it was destroyed.
*/
private Object activateOrDestroy(final Object obj) {
try {
objectPool.getFactory().activateObject(obj);
} catch (Exception e1) {
try {
objectPool.getFactory().destroyObject(obj);
} catch (Exception e2) {
// ignore
}
return null; // try again
}
return obj;
}
public String toString() {
return "GrowManager{}";
}
} java/org/mcarthur/sandy/commons/pool/composite/IdleEvictorLender.java 0000644 0000765 0000765 00000007570 10373452750 030036 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.util.TimerTask;
/**
* A {@link Lender} that evicts objects that have been idle for a while.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
final class IdleEvictorLender extends EvictorLender implements Serializable {
private static final long serialVersionUID = 2422278988668384937L;
/**
* Time, in milli-seconds, before the idle objects are evicted.
*/
private long idleTimeoutMillis = 60L * 60L * 1000L; // 60 minute
/**
* Create a lender that will evict idle objects after a period of time.
*
* @param delegate delegate the lender to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
IdleEvictorLender(final Lender delegate) throws IllegalArgumentException {
super(delegate);
}
protected EvictorReference createReference(final Object obj) {
return new IdleEvictorReference(obj);
}
/**
* Get the time, in milli-seconds, before the idle objects are evicted.
* @return the time, in milli-seconds, before the idle objects are evicted.
*/
public long getIdleTimeoutMillis() {
return idleTimeoutMillis;
}
/**
* Set the time, in milli-seconds, before the idle objects are evicted.
*
* @param idleTimeoutMillis the time, in milli-seconds, before the idle objects are evicted.
*/
public void setIdleTimeoutMillis(final long idleTimeoutMillis) {
this.idleTimeoutMillis = idleTimeoutMillis;
}
public String toString() {
return "IdleEvictor{" +
"idleTimeoutMillis=" + idleTimeoutMillis +
", delegate=" + super.toString() +
'}';
}
/**
* An evictor reference that allows idle objects to be evicted for being idle for a period of time.
*/
private class IdleEvictorReference implements EvictorReference {
/**
* The idle object.
*/
private Object referant;
/**
* The timer task that when run will evict the idle object.
*/
private final TimerTask task;
/**
* Create an evictor reference that allows idle objects to be evicted for being idle for a period of time.
*
* @param referant the idle object.
*/
IdleEvictorReference(final Object referant) {
this.referant = referant;
task = new IdleEvictorTask();
getTimer().schedule(task, idleTimeoutMillis);
}
public Object get() {
return referant;
}
public void clear() {
task.cancel();
if (referant instanceof EvictorReference) {
((EvictorReference)referant).clear();
}
referant = null;
}
/**
* A timer task that when run evicts the idle object.
*/
private class IdleEvictorTask extends TimerTask {
/**
* Evict the idle object.
*/
public void run() {
synchronized(getObjectPool().getPool()) {
referant = null;
}
}
}
}
} java/org/mcarthur/sandy/commons/pool/composite/IdleLimitManager.java 0000644 0000765 0000765 00000005177 10373432430 027634 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.ListIterator;
/**
* A {@link Manager} that limit the number of idle objects associate with the pool.
*
* @see CompositeObjectPoolFactory#setMaxIdle(int)
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
final class IdleLimitManager extends DelegateManager implements Serializable {
private static final long serialVersionUID = -8037318859951361774L;
/**
* Maximum number of idle objects in the idle object pool.
*/
private int maxIdle = 0;
IdleLimitManager(final Manager delegate) throws IllegalArgumentException {
super(delegate);
}
/**
* Possible remove an idle object and delegates to another {@link Manager}.
*
* @param obj the object to return to the pool.
* @throws Exception as thrown by {@link PoolableObjectFactory#passivateObject(Object)}.
*/
public void returnToPool(final Object obj) throws Exception {
assert Thread.holdsLock(objectPool.getPool());
if (maxIdle > 0 && maxIdle <= objectPool.getNumIdle()) {
// XXX Does this remove the most stale object in
final ListIterator iter = objectPool.getLender().listIterator();
iter.next();
iter.remove();
}
super.returnToPool(obj);
}
/**
* Maximum number of idle objects in the idle object pool.
*
* @return maximum number of idle objects in the idle object pool.
*/
public int getMaxIdle() {
return maxIdle;
}
/**
* Set the maximum number of idle objects in the idle object pool.
*
* @param maxIdle maximum number of idle objects.
*/
public void setMaxIdle(final int maxIdle) {
this.maxIdle = maxIdle;
}
public String toString() {
return "IdleLimitManager{" +
"maxIdle=" + maxIdle +
", delegate=" + super.toString() +
'}';
}
} java/org/mcarthur/sandy/commons/pool/composite/InvalidEvictorLender.java 0000644 0000765 0000765 00000013655 10373452750 030550 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
import java.util.TimerTask;
/**
* A {@link Lender} that evicts objects from the idle pool if they fail
* {@link PoolableObjectFactory#validateObject(Object) validation}.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
final class InvalidEvictorLender extends EvictorLender implements Serializable {
private static final long serialVersionUID = -3200445766813431919L;
/**
* Time, in milli-seconds, between the checks that idle objects are still
* {@link PoolableObjectFactory#validateObject(Object) valid}.
*/
private long validationFrequencyMillis = 10L * 60L * 1000L; // 10 minute
/**
* Create a lender that will evict idle object if they fail to pass
* {@link PoolableObjectFactory#validateObject(Object)}.
*
* @param delegate delegate the lender to delegate to, must not be null
.
* @throws IllegalArgumentException when delegate
is null
.
*/
InvalidEvictorLender(final Lender delegate) throws IllegalArgumentException {
super(delegate);
}
protected EvictorReference createReference(final Object obj) {
return new InvalidEvictorReference(obj);
}
/**
* Get the time, in milli-seconds, between the checks that idle objects are still
* {@link PoolableObjectFactory#validateObject(Object) valid}.
*
* @return time, in milli-seconds, between the checks that idle objects are still valid.
*/
public long getValidationFrequencyMillis() {
return validationFrequencyMillis;
}
/**
* Set the time, in milli-seconds, between the checks that idle objects are still
* {@link PoolableObjectFactory#validateObject(Object) valid}.
*
* @param validationFrequencyMillis time, in milli-seconds, between the checks that idle objects are still valid.
* @throws IllegalArgumentException if validationFrequencyMillis is negative
*/
public void setValidationFrequencyMillis(final long validationFrequencyMillis) throws IllegalArgumentException {
if (validationFrequencyMillis < 0) {
throw new IllegalArgumentException("validationFrequencyMillis must not be negative. was: " + validationFrequencyMillis);
}
this.validationFrequencyMillis = validationFrequencyMillis;
}
public String toString() {
return "InvalidEvictor{" +
"validationFrequencyMillis=" + validationFrequencyMillis +
", delegate=" + super.toString() +
'}';
}
/**
* An evictor reference that evicts idle objects that fail
* {@link PoolableObjectFactory#validateObject(Object) validation}.
*/
private class InvalidEvictorReference implements EvictorReference {
/**
* The idle object.
*/
private Object referant;
/**
* The timer task that when run will validate and possibly evict the idle object.
*/
private final TimerTask task;
/**
* Create an evictor reference that checks if idle objects are still valid.
*
* @param referant the idle object.
*/
InvalidEvictorReference(final Object referant) {
this.referant = referant;
task = new InvalidEvictorTask();
getTimer().schedule(task, validationFrequencyMillis, validationFrequencyMillis);
}
public Object get() {
return referant;
}
public void clear() {
task.cancel();
if (referant instanceof EvictorReference) {
((EvictorReference)referant).clear();
}
referant = null;
}
/**
* A TimerTask that checks the {@link PoolableObjectFactory#validateObject(Object) validity} of it idle object.
* If the idle object fails validation then the {@link InvalidEvictorLender.InvalidEvictorReference} is
* {@link InvalidEvictorReference#clear() cleared}.
*/
private class InvalidEvictorTask extends TimerTask {
/**
* Check the idle object for {@link PoolableObjectFactory#validateObject(Object) validity} and
* {@link InvalidEvictorReference#clear() clear} it if it fails.
*/
public void run() {
// Skip some synchronization if we can
if (referant == null) {
cancel();
return;
}
final PoolableObjectFactory factory = getObjectPool().getFactory();
synchronized(getObjectPool().getPool()) {
if (referant == null) {
cancel();
return;
}
try {
factory.activateObject(referant);
if (factory.validateObject(referant)) {
factory.passivateObject(referant);
} else {
factory.destroyObject(referant);
clear();
}
} catch (Exception e) {
clear();
}
}
}
}
}
} java/org/mcarthur/sandy/commons/pool/composite/KeyedPoolableObjectFactoryAdapter.java 0000644 0000765 0000765 00000010470 10373377730 033167 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import java.io.Serializable;
/**
* Adapter to let an {@link ObjectPool} use a {@link KeyedPoolableObjectFactory}. Before first use
* {@link #setCompositeKeyedObjectPool(CompositeKeyedObjectPool)} must be called so that a reference to the
* {@link ThreadLocal} used to pass the key through the {@link ObjectPool} can be aquired.
*
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
final class KeyedPoolableObjectFactoryAdapter implements PoolableObjectFactory, Serializable {
private static final long serialVersionUID = 8664321206626066192L;
/**
* The keyed object factory we're adapting.
*/
// XXX: Add better handling of when this instance is not Serializable
private final KeyedPoolableObjectFactory delegate;
/**
* Where we get the current key before delegating to the keyed object factory.
* On deserialization this will be set by {@link CompositeKeyedObjectPool}'s constructor.
*/
private transient ThreadLocal keys;
KeyedPoolableObjectFactoryAdapter(final KeyedPoolableObjectFactory delegate) {
this.delegate = delegate;
}
/**
* The keyed object pool that uses this adapter.
*
* @param pool the keyed object pool that uses this adapter.
*/
public void setCompositeKeyedObjectPool(final CompositeKeyedObjectPool pool) {
if (pool == null) {
throw new IllegalArgumentException("pool must not be null.");
}
if (pool.getKeys() == null) {
throw new IllegalArgumentException("pool's keys must not be null.");
}
keys = pool.getKeys();
}
/**
* Creates an instance that can be returned by the pool.
*
* @return an instance that can be returned by the pool.
* @throws Exception when the delegate does.
*/
public Object makeObject() throws Exception {
return delegate.makeObject(keys.get());
}
/**
* Destroys an instance no longer needed by the pool.
*
* @param obj the instance to be destroyed
* @throws Exception when the delegate does.
*/
public void destroyObject(final Object obj) throws Exception {
delegate.destroyObject(keys.get(), obj);
}
/**
* Ensures that the instance is safe to be returned by the pool.
* Returns false if this object should be destroyed.
* @param obj the instance to be validated
* @return false if this obj is not valid and should
* be dropped from the pool, true otherwise.
*/
public boolean validateObject(final Object obj) {
return delegate.validateObject(keys.get(), obj);
}
/**
* Reinitialize an instance to be returned by the pool.
*
* @param obj the instance to be activated
* @throws Exception when the delegate does.
*/
public void activateObject(final Object obj) throws Exception {
delegate.activateObject(keys.get(), obj);
}
/**
* Uninitialize an instance to be returned to the pool.
*
* @param obj the instance to be passivated
* @throws Exception when the delegate does.
*/
public void passivateObject(final Object obj) throws Exception {
delegate.passivateObject(keys.get(), obj);
}
/**
* This adapter's delegate keyed object factory. Needed by {@link CompositeKeyedObjectPoolFactory#getKeyedFactory()}.
*
* @return this adapter's delegate keyed object factory.
*/
KeyedPoolableObjectFactory getDelegate() {
return delegate;
}
} java/org/mcarthur/sandy/commons/pool/composite/Lender.java 0000644 0000765 0000765 00000006447 10373003300 025665 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.util.ListIterator;
/**
* Handles how idle objects are added and removed from the idle object pool.
* Implementations are expected to be called from a synchronized context on the idle object pool.
*
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
interface Lender {
/**
* Called once to associate this manager with an object pool by the {@link CompositeObjectPool} constructor.
*
* @param objectPool the pool to associate with.
* @throws IllegalArgumentException if objectPool
is null
.
* @throws IllegalStateException if this method is called more than once.
*/
public void setCompositeObjectPool(CompositeObjectPool objectPool) throws IllegalArgumentException, IllegalStateException;
/**
* Take an object from the idle object pool.
*
* @return a previously idle object.
*/
public Object borrow();
/**
* Return an object to the idle object pool. Implementations must call {@link Object#notifyAll()} on the idle object
* pool so the {@link WaitLimitManager} can work.
*
* @param obj the object to return to the idle object pool.
*/
public void repay(Object obj);
/**
* Returns a list iterator of the elements in this pool. The list iterator should be implemented such that the first
* element retuend by {@link ListIterator#next()} is most likely to be the least desirable idle object.
* Implementations of the {@link Lender} interface that wrap/unwrap idle objects should do the same here.
* Clients should be aware that it is likely that {@link ListIterator#next()} or {@link ListIterator#previous()}
* will return null. Client that receive a null should call {@link ListIterator#remove()} but {@link Lender}s that
* receive an unexpected null must never automatically {@link ListIterator#remove()} an element as that would break
* the {@link ListIterator#hasNext()} and {@link ListIterator#hasPrevious()} contracts for the client.
* Use of this list iternator must be synchronized on the {@link CompositeObjectPool#getPool() pool}. Clients
* that synchronize on the {@link CompositeObjectPool#getPool() pool} should make special effort to be quick or not
* hold on to that lock for too long of a period as no other threads will be able to access the pool at the same
* time.
*
* @return a list iterator of the elements in this pool.
*/
public ListIterator listIterator();
/**
* Return the size of the idle object pool.
*
* @return the size of the idle object pool the lender is accessing.
*/
public int size();
} java/org/mcarthur/sandy/commons/pool/composite/LifoLender.java 0000644 0000765 0000765 00000002577 10373450326 026515 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
/**
* A Last In First Out (LIFO) {@link Lender}.
*
* @see BorrowType#LIFO
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class LifoLender extends AbstractLender implements Serializable {
private static final long serialVersionUID = 5836740439617614901L;
public Object borrow() {
final List pool = getObjectPool().getPool();
assert Thread.holdsLock(pool);
if (pool instanceof LinkedList) {
return ((LinkedList)pool).removeLast();
} else {
return pool.remove(pool.size() - 1);
}
}
public String toString() {
return "LIFO";
}
} java/org/mcarthur/sandy/commons/pool/composite/LimitBehavior.java 0000644 0000765 0000765 00000004334 10373533354 027224 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.NoSuchElementException;
/**
* Specifies the behavior of when the max number of active objects has been reached.
*
* @see CompositeObjectPoolFactory#setLimitBehavior(LimitBehavior)
* @see CompositeKeyedObjectPoolFactory#setLimitBehavior(LimitBehavior)
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
public final class LimitBehavior implements Serializable {
private static final long serialVersionUID = -4325661345028907604L;
/**
* When the number of active objects has been reached fail with a {@link NoSuchElementException} instead of
* returning a new object.
*/
public static final LimitBehavior FAIL = new LimitBehavior("FAIL");
/**
* When the number of active objects has been reached wait for the specified amount of time before failing with
* a {@link NoSuchElementException}.
*/
public static final LimitBehavior WAIT = new LimitBehavior("WAIT");
/**
* enum name.
*/
private final String name;
private LimitBehavior(final String name) {
this.name = name;
}
public String toString() {
return name;
}
// Autogenerated with Java 1.5 enums
public static LimitBehavior[] values() {
return new LimitBehavior[] {FAIL, WAIT};
}
// necessary for serialization
private static int nextOrdinal = 0;
private final int ordinal = nextOrdinal++;
private Object readResolve() throws ObjectStreamException {
return values()[ordinal];
}
} java/org/mcarthur/sandy/commons/pool/composite/Manager.java 0000644 0000765 0000765 00000005134 10373003300 026016 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import org.apache.commons.pool.PoolableObjectFactory;
import java.util.NoSuchElementException;
/**
* Controls the behavior of how the pool grown or errors.
* Managers are expected to transition an object from an active or idle state and vice versa.
* Implementations are expected to be called from a synchronized context on the idle object pool.
*
* @see ExhaustionBehavior
* @see LimitBehavior
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
interface Manager {
/**
* Called once to associate this manager with an object pool by the {@link CompositeObjectPool} constructor.
*
* @param objectPool the pool to associate with.
* @throws IllegalArgumentException if objectPool
is null
.
* @throws IllegalStateException if this method is called more than once.
*/
public void setCompositeObjectPool(CompositeObjectPool objectPool) throws IllegalArgumentException, IllegalStateException;
/**
* Retreives the next object from the pool. Objects from the pool will be
* {@link PoolableObjectFactory#activateObject(Object) activated} and
* {@link PoolableObjectFactory#validateObject(Object) validated}.
* Newly {@link PoolableObjectFactory#makeObject() created} objects will not be activated or validated.
*
* @return a new or activated object.
* @throws NoSuchElementException if the pool is empty and no new object can be created.
* @throws Exception usually from {@link PoolableObjectFactory} methods.
*/
public Object nextFromPool() throws NoSuchElementException, Exception;
/**
* Return an object to the pool. Object will be {@link PoolableObjectFactory#passivateObject(Object) passivated}.
*
* @param obj the object to return to the pool.
* @throws Exception as thrown by {@link PoolableObjectFactory#passivateObject(Object)}.
*/
public void returnToPool(Object obj) throws Exception;
} java/org/mcarthur/sandy/commons/pool/composite/NullLender.java 0000644 0000765 0000765 00000004352 10373003300 026511 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
import java.util.Collections;
import java.util.ListIterator;
/**
* Neither borrow nor return objects.
*
* @see BorrowType#NULL
* @author Sandy McArthur
* @since #.#
* @version $Revision$ $Date$
*/
final class NullLender implements Lender, Serializable {
private static final long serialVersionUID = -135471856936204860L;
/**
* Called once to associate this manager with an object pool by the {@link CompositeObjectPool} constructor.
*
* @param objectPool the pool to associate with.
* @throws IllegalArgumentException if objectPool
is null
.
* @throws IllegalStateException if this method is called more than once.
*/
public void setCompositeObjectPool(final CompositeObjectPool objectPool) throws IllegalArgumentException, IllegalStateException {
// nothing
}
/**
* Return null
.
*
* @return null
.
*/
public Object borrow() {
return null;
}
/**
* Discards the object.
*
* @param obj the object to be discarded.
*/
public void repay(final Object obj) {
// nothing
}
/**
* Returns a list iterator from an empty list.
*
* @return a list iterator from an empty list.
*/
public ListIterator listIterator() {
return Collections.EMPTY_LIST.listIterator();
}
/**
* Return 0
.
*
* @return 0
.
*/
public int size() {
return 0;
}
public String toString() {
return "NULL";
}
} java/org/mcarthur/sandy/commons/pool/composite/NullTracker.java 0000644 0000765 0000765 00000003274 10373003300 026675 0 ustar sandymac sandymac 0000000 0000000 /*
* 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.mcarthur.sandy.commons.pool.composite;
import java.io.Serializable;
/**
* Doesn't actually track active objects. Not compatiable with any {@link ActiveLimitManager} implementation.
*
* @see TrackingType#NULL
* @author Sandy McArthur
* @version $Revision$ $Date$
* @since #.#
*/
final class NullTracker implements Tracker, Serializable {
private static final long serialVersionUID = -5846405955762769678L;
/**
* Don't do anything.
*
* @param obj was borrowed from the pool.
*/
public void borrowed(final Object obj) {
}
/**
* Don't do anything.
*
* @param obj being returned to the pool.
*/
public void returned(final Object obj) {
}
/**
* Throws {@link UnsupportedOperationException}.
*
* @return doesn't, always throws an {@link UnsupportedOperationException}.
* @throws UnsupportedOperationException
*/
public int getBorrowed() {
throw new UnsupportedOperationException("tracking disabled");
}
public String toString() {
return "NullTracker{}";
}
}
java/org/mcarthur/sandy/commons/pool/composite/package.html 0000644 0000765 0000765 00000022162 10373541151 026075 0 ustar sandymac sandymac 0000000 0000000
Composite [Keyed] Object Pool implementation.
About
The classes in this package are used to implement the {@link org.apache.commons.pool.ObjectPool} and
the {@link org.apache.commons.pool.KeyedObjectPool} interfaces building the desired feature set via
object composition. Almost every interesting class or method in this package is package-private or
privately scoped. This is intentional as clients of this code should not care about implementations
as much as the desired feature set. This should make future transitions to more correct or better
performant code painless or at least much less painful.
Public Code Tour
Factories
There are two object pool factories in this package:
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPoolFactory} and
{@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPoolFactory}.
{@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPoolFactory}
actually delegates almost all of it's work to the regular
composite object pool factory. The only interesting part about it is in the
{@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPoolFactory#setKeyedFactory} method
where it wraps the {@link org.apache.commons.pool.KeyedPoolableObjectFactory} in an adapter that uses a
ThreadLocal to pass the key through the {@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPool}
backing the {@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPool} for that particular key.
More on that later.
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPoolFactory} does all of it's heavy lifting in
three methods:
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPoolFactory#getLender},
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPoolFactory#getManager}, and
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPoolFactory#getTracker}.
All other methods are little more than java bean pattern getters and setters.
Those three methods check that the factory has not been configured in an invalid way and compose the
each of the three components that make up a {@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPool}.
Also, if possible any optimizations are made here.
Type safe enums
Any public class not mentioned in the above facades or factories sections is a type safe enum used by the factories
to specify the desired configuration. Type safe enums are used for two reasons. First, they represent the desired
feature set as opposed to a specific implementation. Second, by using them it is nearly impossible to configure
a factory in an invalid configuration.
Private Code Tour
The following is intended to help those who wish to better understand the design of the composite object pool
implementation.
Object Pools
Behind the scenes there are two package-private object pool implementations:
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPool} and
{@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPool}.
CompositeKeyedObjectPool
The {@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPool} is implemented as a map of keys to
object pools. When a new key is used it uses a {@link org.apache.commons.pool.ObjectPoolFactory} to create an
object pool for that key. I do not believe there is anything in
{@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPool} that requires the use of
{@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPool} to back each key. Also there is nothing to
prevent the use of {@link org.apache.commons.pool.ObjectPool}s that are configured differently for each key
but this feature seemed to have minimal utility. Such functionality could be obtained via careful use of the
{@link org.mcarthur.sandy.commons.pool.composite.CompositeKeyedObjectPoolFactory#createPool(org.apache.commons.pool.ObjectPoolFactory)}
method.
CompositeObjectPool
The {@link org.mcarthur.sandy.commons.pool.composite.CompositeObjectPool} is the heart and soul of this object pool
implementation. Again, delegation is what makes this sucker tick. There are three component types the composite
object pool delegates it's work to and from where it acquires it's feature set.
Lender
A {@link org.mcarthur.sandy.commons.pool.composite.Lender} maintains idle objects and the order in which objects are
borrowed. It is common for lenders to be stacked to get the desired functionality. There are three terminating
lenders: {@link org.mcarthur.sandy.commons.pool.composite.FifoLender},
{@link org.mcarthur.sandy.commons.pool.composite.LifoLender}, and
{@link org.mcarthur.sandy.commons.pool.composite.NullLender}.
Next there is a {@link org.mcarthur.sandy.commons.pool.composite.SoftLender} which can be used to allow garbage
collection of idle objects. It would be possible to create a WeakLender but I'm not sure I see any utility in that.
Finally there is a class of {@link org.mcarthur.sandy.commons.pool.composite.EvictorLender}s that are used to
preform idle object eviction.
EvictorLenders
There are two {@link org.mcarthur.sandy.commons.pool.composite.EvictorLender}s that can be chained together:
{@link org.mcarthur.sandy.commons.pool.composite.IdleEvictorLender} and
{@link org.mcarthur.sandy.commons.pool.composite.InvalidEvictorLender}.
Both evictor types use a {@link java.util.Timer} to schedule their work. The Timer class claims to be very scalable
which is good because there will be a lot of {@link java.util.TimerTask}s in a large object pool.
Each of the evictor types create a TimerTask that will run at a future time to possibly evict one idle object.
This design makes idle object eviction quite deterministic and limits contention for the object pool to the bare
minimum.
Manager
{@link org.mcarthur.sandy.commons.pool.composite.Manager}: a manager does most of the heavy lifting between a
{@link org.mcarthur.sandy.commons.pool.composite.Lender} and a
{@link org.mcarthur.sandy.commons.pool.composite.Tracker}. A manager is responsible for activating and validating
idle objects and passivating and possibly validating active objects. It is also responsible for controlling the
growth and size of the pool. Managers can also be stacked together to get the desired feature set. There are two
terminating mangers: {@link org.mcarthur.sandy.commons.pool.composite.FailManager} and
{@link org.mcarthur.sandy.commons.pool.composite.GrowManager}. These two manager interact with the poolable object
factory and the lenders to activate idle object or create new ones.
{@link org.mcarthur.sandy.commons.pool.composite.IdleLimitManager} is a unique in that it is really the only manager
that does any interesting work in the {@link org.mcarthur.sandy.commons.pool.composite.IdleLimitManager#returnToPool}
method. Finally there are two {@link org.mcarthur.sandy.commons.pool.composite.ActiveLimitManager}s that implement
the behaviors for when a pool has reached it's limit of active objects:
{@link org.mcarthur.sandy.commons.pool.composite.FailLimitManager} and
{@link org.mcarthur.sandy.commons.pool.composite.WaitLimitManager}.
Tracker
{@link org.mcarthur.sandy.commons.pool.composite.Tracker}: a tracker's sole responsibility is keeping track of
active objects borrowed from the pool. A tracker will never touch an object that is considered to be idle. The
{@link org.mcarthur.sandy.commons.pool.composite.NullTracker} and
{@link org.mcarthur.sandy.commons.pool.composite.SimpleTracker} classes are very simple. The
{@link org.mcarthur.sandy.commons.pool.composite.ReferenceTracker} is much more interesting. It can detect when a
borrowed object is not returned to the pool (assuming the garbage collector does it's thing in a timely manner).
Most of it's complexity comes from the need to carefully track borrowed objects without creating a strong reference
to them. The trickery needed to make this work is rather neat, especially when the
{@link org.mcarthur.sandy.commons.pool.composite.DebugTracker} is used.
@author Sandy McArthur