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

svn commit: r387630 [3/4] - in /jakarta/commons/proper/pool/contrib/composite-pool: ./ java/ java/org/ java/org/mcarthur/ java/org/mcarthur/sandy/ java/org/mcarthur/sandy/commons/ java/org/mcarthur/sandy/commons/pool/ java/org/mcarthur/sandy/commons/po...

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/KeyedPoolableObjectFactoryAdapter.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/KeyedPoolableObjectFactoryAdapter.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/KeyedPoolableObjectFactoryAdapter.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/KeyedPoolableObjectFactoryAdapter.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,128 @@
+/*
+ * 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 <tt>false</tt> if this object should be destroyed.
+     * @param obj the instance to be validated
+     * @return <tt>false</tt> if this <i>obj</i> is not valid and should
+     *         be dropped from the pool, <tt>true</tt> 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;
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Lender.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Lender.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Lender.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Lender.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,78 @@
+/*
+ * 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 <code>objectPool</code> is <code>null</code>.
+     * @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 <b>must be</b> 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();
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LifoLender.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LifoLender.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LifoLender.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LifoLender.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,48 @@
+/*
+ * 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";
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LimitBehavior.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LimitBehavior.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LimitBehavior.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LimitBehavior.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,72 @@
+/*
+ * 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];
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Manager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Manager.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Manager.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Manager.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,64 @@
+/*
+ * 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 <code>objectPool</code> is <code>null</code>.
+     * @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;
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullLender.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullLender.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullLender.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullLender.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,85 @@
+/*
+ * 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 <code>objectPool</code> is <code>null</code>.
+     * @throws IllegalStateException if this method is called more than once.
+     */
+    public void setCompositeObjectPool(final CompositeObjectPool objectPool) throws IllegalArgumentException, IllegalStateException {
+        // nothing
+    }
+
+    /**
+     * Return <code>null</code>.
+     *
+     * @return <code>null</code>.
+     */
+    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 <code>0</code>.
+     *
+     * @return <code>0</code>.
+     */
+    public int size() {
+        return 0;
+    }
+
+    public String toString() {
+        return "NULL";
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullTracker.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullTracker.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullTracker.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullTracker.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,62 @@
+/*
+ * 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{}";
+    }
+}

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ReferenceTracker.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ReferenceTracker.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ReferenceTracker.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ReferenceTracker.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,214 @@
+/*
+ * 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.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Keeps track of active objects with {@link Reference}s and detectes when they are not returned to the pool.
+ *
+ * @see TrackingType#REFERENCE
+ * @author Sandy McArthur
+ * @version $Revision$ $Date$
+ * @since #.#
+ */
+class ReferenceTracker implements Tracker, Serializable {
+
+    private static final long serialVersionUID = 3271870427019790961L;
+
+    /**
+     * ReferenceQueue of borrowed objects so we can detect when they have been garbage collected instead of being
+     * returned to the pool.
+     */
+    protected final transient ReferenceQueue rq = new ReferenceQueue();
+
+    /**
+     * Map used to track active objects.
+     */
+    protected final transient Map map = Collections.synchronizedMap(new HashMap());
+
+    /**
+     * The number of borrowed objects that were lost to the garbage collector.
+     */
+    private transient int lost = 0;
+
+    public void borrowed(final Object obj) {
+        workQueue();
+        final IdentityReference ref;
+        synchronized (rq) {
+            ref = wrapBorrowed(obj);
+        }
+        map.put(ref.getKey(), ref);
+    }
+
+    /**
+     * Wrap the object in a reference.
+     *
+     * @param obj the object to be wrapped.
+     * @return a type of reference around obj.
+     */
+    protected IdentityReference wrapBorrowed(final Object obj) {
+        return new IdentityWeakReference(obj, rq);
+    }
+
+    /**
+     * Stop tracking an active object. Remove it from the active object {@link #map} and remove it from the reference
+     * queue.
+     *
+     * @param obj a returning active object.
+     * @throws IllegalStateException when an object that wasn't brorrowed from this pool is returned.
+     */
+    public void returned(final Object obj) throws IllegalStateException {
+        workQueue();
+        final IdentityKey key = new IdentityKey(obj);
+        final IdentityReference ref = (IdentityReference)map.remove(key);
+        if (ref != null) {
+            ref.clear();
+        } else {
+            throw new IllegalStateException("Cannot return an object that wasn't borrowed from this pool or has already been returned to this pool. " + obj);
+        }
+    }
+
+    public int getBorrowed() {
+        workQueue();
+        return map.size();
+    }
+
+    /**
+     * Work the {@link #rq reference queue} to detected any lost objects. This calls
+     * {@link #referenceToBeRemoved(ReferenceTracker.IdentityReference)} just before removal from the {@link #map}.
+     */
+    private void workQueue() {
+        synchronized (rq) {
+            for (Reference ref = rq.poll(); ref != null; ref = rq.poll()) {
+                final IdentityReference identRef = (IdentityReference)ref;
+                referenceToBeRemoved(identRef);
+                map.remove(identRef.getKey());
+                lost++;
+            }
+        }
+    }
+
+    /**
+     * Give sub-classes a chance to take action just before a reference is removed. The parameter <code>ref</code> will
+     * be a {@link Reference} aquired from the {@link #wrapBorrowed(Object)} method.
+     *
+     * @param ref the reference that is being removed from the reference queue.
+     */
+    protected void referenceToBeRemoved(final IdentityReference ref) {
+        // nothing to do here
+    }
+
+    /**
+     * Get the number of borrowed objects that were lost. An object is lost when it is borrowed from a pool
+     * and garbage collected instead of being returned.
+     *
+     * @return the number of borrowed objects that were lost.
+     */
+    protected int getLost() {
+        return lost;
+    }
+
+    public String toString() {
+        return "ReferenceTracker{" +
+                "active=" + map.size() +
+                ", lost=" + getLost() +
+                '}';
+    }
+
+    /**
+     * A wrapper for an object has an {@link #equals(Object)} and {@link #hashCode()} based on the
+     * {@link System#identityHashCode(Object) identityHashCode} of an object. This is needed else
+     * {@link ReferenceTracker#map} could not find and track more than one object that are
+     * {@link Object#equals(Object) equal}. If the JDK ever adds a WeakIdentityHashMap we should use that instead.
+     */
+    protected static final class IdentityKey {
+
+        /**
+         * The {@link System#identityHashCode(Object)} of the object.
+         */
+        private final int ident; // XXX: Going need something more than this on 64 bit systems.
+
+        IdentityKey(final Object obj) {
+            this(System.identityHashCode(obj));
+        }
+
+        IdentityKey(final int ident) {
+            this.ident = ident;
+        }
+
+        public int hashCode() {
+            return ident;
+        }
+
+        public boolean equals(final Object obj) {
+            if (this == obj) return true;
+            if (obj == null || getClass() != obj.getClass()) return false;
+
+            final IdentityKey that = (IdentityKey)obj;
+
+            return ident == that.ident;
+        }
+    }
+
+    /**
+     * Implementator of this interface should usually also extend a {@link Reference} class.
+     */
+    protected interface IdentityReference {
+
+        /**
+         * A key that can be used by a map to store/find this reference but does not make this reference strongly
+         * reachable.
+         *
+         * @return key to store/find this reference.
+         */
+        public IdentityKey getKey();
+
+        /**
+         * Clears this reference.
+         *
+         * @see Reference#clear()
+         */
+        public void clear();
+    }
+
+    /**
+     * A {@link WeakReference} that keeps track of enough information to create an {@link ReferenceTracker.IdentityKey}.
+     */
+    private static final class IdentityWeakReference extends WeakReference implements IdentityReference {
+
+        /**
+         * The {@link System#identityHashCode(Object)} of the object.
+         */
+        private final int ident; // XXX: Going need something more than this on 64 bit systems.
+
+        IdentityWeakReference(final Object referent, final ReferenceQueue q) {
+            super(referent, q);
+            ident = System.identityHashCode(referent);
+        }
+
+        public IdentityKey getKey() {
+            return new IdentityKey(ident);
+        }
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SimpleTracker.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SimpleTracker.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SimpleTracker.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SimpleTracker.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+/**
+ * Pretends to track active objects by using a counter. This implementation just increments and decrements a counter and
+ * trusts the user will properly return an object. If the counter goes negative it throws an
+ * {@link IllegalStateException}.
+ *
+ * @see TrackingType#SIMPLE
+ * @author Sandy McArthur
+ * @version $Revision$ $Date$
+ * @since #.#
+ */
+final class SimpleTracker implements Tracker, Serializable {
+
+    private static final long serialVersionUID = -7300626285071421255L;
+
+    /**
+     * The number of "borrowed" or active objects from the pool.
+     */
+    private transient volatile int active = 0;
+
+    /**
+     * Increment {@link #active} by one.
+     *
+     * @param obj was borrowed from the pool.
+     */
+    public void borrowed(final Object obj) {
+        active++;
+    }
+
+    /**
+     * Decrement {@link #active} by one.
+     *
+     * @param obj being returned to the pool.
+     * @throws IllegalStateException when more objects have been returned than borrowed.
+     */
+    public void returned(final Object obj) throws IllegalStateException {
+        if (--active < 0) {
+            active++; // undo, object won't be returned
+            throw new IllegalStateException("More objects returned than were borrowed. Most recent object: " + obj);
+        }
+    }
+
+    /**
+     * The number of "borrowed" or active objects from the pool.
+     *
+     * @return the number of "borrowed" active objects.
+     */
+    public int getBorrowed() {
+        return active;
+    }
+
+    public String toString() {
+        return "SimpleTracker{" +
+                "active=" + active +
+                '}';
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SoftLender.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SoftLender.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SoftLender.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SoftLender.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,164 @@
+/*
+ * 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.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.util.Iterator;
+import java.util.ListIterator;
+
+/**
+ * Wraps object in a {@link SoftReference} before letting a delegate {@link Lender} add them to the idle object pool.
+ * Idle objects that are garbage collected will not be {@link ObjectPool#invalidateObject(Object) invalidated}.  
+ *
+ * @see BorrowType#SOFT_FIFO
+ * @see BorrowType#SOFT_LIFO
+ * @author Sandy McArthur
+ * @since #.#
+ * @version $Revision$ $Date$
+ */
+final class SoftLender extends DelegateLender implements Serializable {
+
+    private static final long serialVersionUID = 8589090657730065177L;
+
+    /**
+     * Create a lnder that allows the garbage collector to remove objects from the idle object pool.
+     *
+     * @param delegate delegate the lender to delegate to, must not be <code>null</code>.
+     * @throws IllegalArgumentException when <code>delegate</code> is <code>null</code>.
+     */
+    SoftLender(final Lender delegate) throws IllegalArgumentException {
+        super(delegate);
+    }
+
+    /**
+     * Unwrap the {@link Reference} from the borrowed object.
+     *
+     * @return a previously idle object.
+     */
+    public Object borrow() {
+        return ((Reference)super.borrow()).get();
+    }
+
+    /**
+     * Wrap the object in a {@link SoftReference} before letting the delegate {@link Lender} return an object to the
+     * idle object pool.
+     *
+     * @param obj the object to return to the idle object pool.
+     */
+    public void repay(final Object obj) {
+        super.repay(new SoftReference(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.
+     *
+     * @return a list iterator of the elements in this pool.
+     */
+    public ListIterator listIterator() {
+        return new SoftListIterator(super.listIterator());
+    }
+
+    /**
+     * Return the size of the idle object pool. Also removes any broken {@link Reference}s so the size is more accurate.
+     *
+     * @return the size of the idle object pool the lender is accessing.
+     */
+    public int size() {
+        final Object lock = getObjectPool().getPool();
+        synchronized (lock) {
+            final Iterator iter = super.listIterator();
+            while (iter.hasNext()) {
+                final Reference ref = (Reference)iter.next();
+                if (ref.get() == null) {
+                    iter.remove();
+                }
+            }
+        }
+        return super.size();
+    }
+
+    public String toString() {
+        return "Soft{" + super.toString() + "}";
+    }
+
+    /**
+     * A {@link ListIterator} that unwrapps {@link Reference}s.
+     */
+    private static class SoftListIterator implements ListIterator {
+        private final ListIterator iter;
+
+        private SoftListIterator(final ListIterator iter) {
+            this.iter = iter;
+        }
+
+        public boolean hasNext() {
+            return iter.hasNext();
+        }
+
+        /**
+         * Unwrap an {@link Reference} and return the next object if it hasn't been garbage collected.
+         *
+         * @return an unwrapped object or <code>null</code> if an object has been garbage collected.
+         * @see ListIterator#next()
+         */
+        public Object next() {
+            final Reference ref = (Reference)iter.next();
+            return ref != null ? ref.get() : null;
+        }
+
+        public boolean hasPrevious() {
+            return iter.hasPrevious();
+        }
+
+        /**
+         * Unwrap an {@link Reference} and return the previous object if it hasn't been garbage collected.
+         *
+         * @return an unwrapped object or <code>null</code> if an object has been garbage collected.
+         * @see ListIterator#previous()
+         */
+        public Object previous() {
+            final Reference ref = (Reference)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);
+        }
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Tracker.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Tracker.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Tracker.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Tracker.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+/**
+ * Tracks active objects. Implementations are expected to be called from a synchronized context so
+ * {@link #getBorrowed()} is accurate.</p>
+ *
+ * <p>{@link #borrowed(Object)} for an object will always be called before {@link #returned(Object)} is called.</p>
+ *
+ * <p>Implementations must not make any assumptions about nor modify the state of the objects it sees. This is simply
+ * a tool for active object accounting.</p>
+ *
+ * @see TrackingType
+ * @author Sandy McArthur
+ * @version $Revision$ $Date$
+ * @since #.#
+ */
+interface Tracker {
+
+    /**
+     * An object has been borrowed from the pool. The object will have been
+     * {@link PoolableObjectFactory#activateObject(Object) activated} and
+     * {@link PoolableObjectFactory#validateObject(Object) validated} and is about to be returned to the client.
+     *
+     * <p>Objects created via {@link ObjectPool#addObject()} are also "borrowed" so that when
+     * {@link ObjectPool#returnObject(Object)} {@link #returned(Object) returns} that object it isn't unexpected.
+     *
+     * @param obj was borrowed from the pool.
+     */
+    public void borrowed(Object obj);
+
+    /**
+     * An object is being {@link ObjectPool#returnObject(Object) returned} to the pool.
+     * {@link ObjectPool#invalidateObject(Object) Invalid} objects are also "returned" via this method.
+     *
+     * @param obj being returned to the pool.
+     */
+    public void returned(Object obj);
+
+    /**
+     * The number of "borrowed" or active objects from the pool.
+     *
+     * @return the number of "borrowed" active objects.
+     */
+    public int getBorrowed();
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/TrackingType.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/TrackingType.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/TrackingType.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/TrackingType.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,88 @@
+/*
+ * 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.lang.ref.WeakReference;
+
+/**
+ * Specifies how active objects are tracked while they are out of the pool.
+ *
+ * @see CompositeObjectPoolFactory#setTrackerType(TrackingType)
+ * @see CompositeKeyedObjectPoolFactory#setTrackerType(TrackingType)
+ * @author Sandy McArthur
+ * @since #.#
+ * @version $Revision$ $Date$
+ */
+public final class TrackingType implements Serializable {
+
+    private static final long serialVersionUID = 181851949909846032L;
+
+    /**
+     * Do not track how objects are borrowed from the pool. While this is the fastest tracking type it is
+     * incompatable with pools that limit the number of objects in the pool.
+     */
+    public static final TrackingType NULL = new TrackingType("NULL");
+
+    /**
+     * Borrowed object tracker that trusts you'll return the objects you borrow. This is the most common method of
+     * tracking active objects. If you return more objects than you borrow then this will throw an
+     * {@link IllegalStateException}.
+     */
+    public static final TrackingType SIMPLE = new TrackingType("SIMPLE");
+
+    /**
+     * Borrowed object tracker that detects when borrowed objects are lost. This implementation keeps track of
+     * borrowed objects with {@link WeakReference weak references} and decrements the active count when lost objects
+     * are garbage collected. The point in time at which an object is detected as being lost is dependant on the
+     * first object borrowed or returned to the pool after garbage collector has collected the lost object. If you
+     * return an object that wasn't borrowed from the pool an {@link IllegalStateException} will be thrown.
+     */
+    public static final TrackingType REFERENCE = new TrackingType("REFERENCE");
+
+    /**
+     * Like {@link #REFERENCE} but prints a stack trace for lost objects from when the object was borrowed from the
+     * pool. The point in time at which the stack trace is printed is dependent on the garbage collector's behavior.
+     */
+    public static final TrackingType DEBUG = new TrackingType("DEBUG");
+
+    /**
+     * enum name.
+     */
+    private final String name;
+
+    private TrackingType(final String name) {
+        this.name = name;
+    }
+
+    public String toString() {
+        return name;
+    }
+
+    // Autogenerated with Java 1.5 enums
+    public static TrackingType[] values() {
+        return new TrackingType[] {NULL, SIMPLE, REFERENCE, DEBUG};
+    }
+
+    // necessary for serialization
+    private static int nextOrdinal = 0;
+    private final int ordinal = nextOrdinal++;
+    private Object readResolve() throws ObjectStreamException {
+        return values()[ordinal];
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/WaitLimitManager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/WaitLimitManager.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/WaitLimitManager.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/WaitLimitManager.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,105 @@
+/*
+ * 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;
+
+/**
+ * Waits for an object to become available if the pool is exhausted. A {@link NoSuchElementException} is thrown if an
+ * object doesn't become available in the specified amount of time. For this to work all {@link Lender}s must call
+ * {@link Object#notifyAll()} on the idle object pool once they've returned an object.
+ *
+ * @see LimitBehavior#WAIT
+ * @author Sandy McArthur
+ * @version $Revision$ $Date$
+ * @since #.#
+ */
+final class WaitLimitManager extends ActiveLimitManager implements Serializable {
+
+    private static final long serialVersionUID = 2536750269978303711L;
+
+    private long maxWaitMillis = 0; // forever
+
+    WaitLimitManager(final Manager delegate) throws IllegalArgumentException {
+        super(delegate);
+    }
+
+    /**
+     * Checks to see how many 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.
+     * @throws InterruptedException   when the {@link Thread} is interrupted.
+     */
+    public Object nextFromPool() throws NoSuchElementException, Exception, InterruptedException {
+        final Object poolLock = objectPool.getPool();
+        assert Thread.holdsLock(poolLock);
+        final long endTime = maxWaitMillis > 0 ? System.currentTimeMillis() + maxWaitMillis : Long.MAX_VALUE;
+        while (maxWaitMillis <= 0 || endTime > System.currentTimeMillis()) {
+            if (Thread.currentThread().isInterrupted()) {
+                throw new InterruptedException();
+            }
+            if (objectPool.getNumActive() < getMaxActive()) {
+                return super.nextFromPool();
+            }
+            // Don't wait if the pool was closed between the start of the while and here.
+            if (objectPool.isOpen()) {
+                final long waitTime = Math.max(1, endTime - System.currentTimeMillis());
+                poolLock.wait(maxWaitMillis > 0 ? waitTime : 0);
+            } else {
+                throw new IllegalStateException("Trying to aquire an object from a closed pool.");
+            }
+        }
+        if (objectPool.isOpen()) {
+            throw new NoSuchElementException("Unable to aquire new object in allowed time of: " + maxWaitMillis);
+        } else {
+            throw new IllegalStateException("Trying to aquire an object from a closed pool.");
+        }
+    }
+
+    /**
+     * The max wait time in milli-seconds for a pooled object to become available.
+     *
+     * @return max wait time in milli-seconds for a pooled object to become available.
+     */
+    public long getMaxWaitMillis() {
+        return maxWaitMillis;
+    }
+
+    /**
+     * Set the max wait time in milli-seconds for a pooled object to become available.
+     * A non-positve value means wait forever.
+     *
+     * @param maxWaitMillis max wait for an object to become available or &lt;= 0 for no limit.
+     */
+    public void setMaxWaitMillis(final long maxWaitMillis) {
+        this.maxWaitMillis = maxWaitMillis;
+    }
+
+    public String toString() {
+        return "WaitLimitManager{" +
+                "maxActive=" + getMaxActive() +
+                ", maxWaitMillis=" + maxWaitMillis +
+                ", delegate=" + super.toString() +
+                '}';
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/package.html?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/package.html (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/package.html Tue Mar 21 13:41:53 2006
@@ -0,0 +1,166 @@
+<!--
+  ~ 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.
+  -->
+
+<!-- $Id: $ -->
+<html>
+<body>
+<p>
+    Composite [Keyed] Object Pool implementation.
+</p>
+
+<h3>About</h3>
+<p>
+    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.
+</p>
+
+<h3>Public Code Tour</h3>
+
+<h4>Factories</h4>
+<p>
+    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}.
+</p>
+<p>
+    {@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.
+</p>
+<p>
+    {@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.
+</p>
+
+<h4>Type safe enums</h4>
+<p>
+    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.
+</p>
+
+<hr width="50%"/>
+
+<h3>Private Code Tour</h3>
+<p>
+    The following is intended to help those who wish to better understand the design of the composite object pool
+    implementation.
+</p>
+
+<h3>Object Pools</h3>
+<p>
+    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}.
+</p>
+
+<h4>CompositeKeyedObjectPool</h4>
+<p>
+    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.
+</p>
+
+<h4>CompositeObjectPool</h4>
+<p>
+    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.
+</p>
+
+<h5>Lender</h5>
+<p>
+    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.
+</p>
+
+<h6>EvictorLenders</h6>
+<p>
+    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.
+</p>
+
+<h5>Manager</h5>
+<p>
+    {@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}.
+</p>
+
+<h5>Tracker</h5>
+<p>
+    {@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.
+</p>
+
+@author Sandy McArthur
+
+</body>
+</html>
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/PerformanceTest.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/PerformanceTest.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/PerformanceTest.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/PerformanceTest.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,624 @@
+/*
+ * 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 org.apache.commons.pool.ObjectPool;
+import org.apache.commons.pool.BasePoolableObjectFactory;
+import org.apache.commons.pool.impl.GenericObjectPool;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Date;
+import java.util.ArrayList;
+import java.util.LinkedList;
+
+/**
+ * A collection of benchmarks to confirm and establish performance properties.
+ *
+ * @author Sandy McArthur
+ * @since #.#
+ * @version $Revision$ $Date$
+ */
+public class PerformanceTest {
+    public static final Object LOCK = new Object();
+    private static final List borrowTypes = Arrays.asList(BorrowType.values());
+    private static final List exhaustionBehaviors = Arrays.asList(ExhaustionBehavior.values());
+    private static final List maxIdles = Arrays.asList(new Integer[] {new Integer(-1), new Integer(10)});
+    private static final List maxActives = Arrays.asList(new Integer[] {new Integer(-1), new Integer(10)});
+    private static final List limitBehaviors = Arrays.asList(LimitBehavior.values());
+    private static final List maxWaits = Arrays.asList(new Integer[] {new Integer(-1), new Integer(50)}); // not sure how to use this
+    private static final List trackingTypes = new ArrayList(Arrays.asList(TrackingType.values()));
+    private static final List validateOnReturns = Arrays.asList(new Boolean[] {Boolean.FALSE, Boolean.TRUE});
+    // evictIdleMillis
+    // evictInvalidFrequencyMillis
+    static {
+        trackingTypes.remove(TrackingType.DEBUG); // based off of TrackingType.REFERENCE and slower (about 1/5 as fast)
+    }
+
+    private Iterator borrowIter = borrowTypes.iterator();
+    private Iterator exhaustionIter = exhaustionBehaviors.iterator();
+    private Iterator maxIdleIter = maxIdles.iterator();
+    private Iterator maxActiveIter = maxActives.iterator();
+    private Iterator limitIter = limitBehaviors.iterator();
+    private Iterator trackingIter = trackingTypes.iterator();
+    private Iterator validateIter = validateOnReturns.iterator();
+
+    private PoolableObjectFactory objectFactory = new IntegerFactory();
+
+    private final CompositeObjectPoolFactory poolFactory = new CompositeObjectPoolFactory(objectFactory);
+
+    private Set ranCombinations = new HashSet();
+
+    private boolean nextCompositeSettings() {
+        boolean newCombination = true;
+        if (!validateIter.hasNext()) {
+            validateIter = validateOnReturns.iterator();
+
+            if (!trackingIter.hasNext()) {
+                trackingIter = trackingTypes.iterator();
+
+                if (!limitIter.hasNext()) {
+                    limitIter = limitBehaviors.iterator();
+
+                    if (!maxActiveIter.hasNext()) {
+                        maxActiveIter = maxActives.iterator();
+
+                        if (!maxIdleIter.hasNext()) {
+                            maxIdleIter = maxIdles.iterator();
+
+                            if (!exhaustionIter.hasNext()) {
+                                exhaustionIter = exhaustionBehaviors.iterator();
+
+                                if (!borrowIter.hasNext()) {
+                                    borrowIter = borrowTypes.iterator();
+                                    newCombination = false;
+                                }
+                                poolFactory.setBorrowType((BorrowType)borrowIter.next());
+                            }
+                            poolFactory.setExhaustionBehavior((ExhaustionBehavior)exhaustionIter.next());
+                        }
+                        poolFactory.setMaxIdle(((Integer)maxIdleIter.next()).intValue());
+                    }
+                    poolFactory.setMaxActive(((Integer)maxActiveIter.next()).intValue());
+                }
+                poolFactory.setLimitBehavior((LimitBehavior)limitIter.next());
+            }
+            poolFactory.setTrackerType((TrackingType)trackingIter.next());
+        }
+        poolFactory.setValidateOnReturn(((Boolean)validateIter.next()).booleanValue());
+
+        return newCombination;
+    }
+
+    private void runEveryComposite(final int seconds) {
+        do {
+            try {
+                final String combination = poolFactory.toString();
+                if (ranCombinations.add(combination)) { // skip dups
+                    ((IntegerFactory)objectFactory).reset();
+                    final ObjectPool pool = poolFactory.createPool();
+                    System.out.print(combination);
+                    System.out.print("\t");
+
+                    testForNumSeconds(seconds, pool);
+                }
+            } catch (Exception e) {
+                // ignore
+            }
+            gc();
+        } while (nextCompositeSettings());
+        ranCombinations.clear();
+    }
+
+    private static void gc() {
+        System.gc();
+        System.gc();
+        System.gc();
+        try {
+            Thread.sleep(500);
+        } catch (InterruptedException e) {
+            // ignored
+        }
+    }
+
+    private static double testForNumSeconds(final int seconds, final ObjectPool pool) throws Exception {
+        // Prime for FAIL exhaust
+        try {
+            if (pool.getNumIdle() == 0) {
+                pool.addObject();
+            }
+        } catch (UnsupportedOperationException uoe) {
+            // ignore
+        }
+
+        long startTime = System.currentTimeMillis();
+        while (startTime == System.currentTimeMillis()) ;
+        startTime = System.currentTimeMillis();
+        final long endTime = startTime + (seconds * 1000);
+        long actualEndTime;
+        int loops = 0;
+        while (endTime >= (actualEndTime = System.currentTimeMillis())) {
+            Object obj = null;
+            try {
+                obj = pool.borrowObject();
+                pool.returnObject(obj);
+            } catch (Exception e) {
+                if (obj != null) {
+                    pool.invalidateObject(obj);
+                }
+            }
+            loops++;
+        }
+        final double borrowsPerSecond = ((double)loops / ((double)(actualEndTime - startTime) / 1000D));
+        System.out.println(borrowsPerSecond + " borrows per second");
+        return borrowsPerSecond;
+    }
+
+
+    private void runEveryGeneric(final int seconds) {
+        ((IntegerFactory)objectFactory).reset();
+        ObjectPool pool = new GenericObjectPool(objectFactory, -1, GenericObjectPool.WHEN_EXHAUSTED_GROW, -1, -1, 0, true, false, -1, -1, -1, false);
+        try {
+            System.out.print("GenericObjectPool{maxActive=-1, maxIdle=-1}");
+            System.out.print("\t");
+            testForNumSeconds(seconds, pool);
+            gc();
+
+            pool = new GenericObjectPool(objectFactory, 10, GenericObjectPool.WHEN_EXHAUSTED_GROW, -1, -1, 0, true, false, -1, -1, -1, false);
+            System.out.print("GenericObjectPool{maxActive=10, maxIdle=-1}");
+            System.out.print("\t");
+            testForNumSeconds(seconds, pool);
+            gc();
+
+            pool = new GenericObjectPool(objectFactory, -1, GenericObjectPool.WHEN_EXHAUSTED_GROW, -1, 10, 0, true, false, -1, -1, -1, false);
+            System.out.print("GenericObjectPool{maxActive=-1, maxIdle=10}");
+            System.out.print("\t");
+            testForNumSeconds(seconds, pool);
+            gc();
+
+            pool = new GenericObjectPool(objectFactory, 10, GenericObjectPool.WHEN_EXHAUSTED_GROW, -1, 10, 0, true, false, -1, -1, -1, false);
+            System.out.print("GenericObjectPool{maxActive=10, maxIdle=10}");
+            System.out.print("\t");
+            testForNumSeconds(seconds, pool);
+            gc();
+        } catch (Exception e) {
+
+        }
+    }
+
+
+    private void compareCompositeGerneic(final int seconds) {
+        final CompareCompositeGeneric ccg = new CompareCompositeGeneric();
+        do {
+            gc();
+
+            ObjectPool objectPool;
+            gc();
+
+            try {
+                System.out.print("GOP:noTestOnBorrow\t" + ccg + "\t");
+                objectPool = ccg.getGeneric();
+                ((GenericObjectPool)objectPool).setTestOnBorrow(false);
+                testForNumSeconds(seconds, objectPool);
+            } catch (Exception e) {
+                System.out.println("exception thrown! " + e.getMessage());
+            }
+
+            double gopBPS = -1;
+            try {
+                System.out.print("GenericObjectPool\t" + ccg + "\t");
+                objectPool = ccg.getGeneric();
+                ((GenericObjectPool)objectPool).setTestOnBorrow(true);
+                gopBPS = testForNumSeconds(seconds, objectPool);
+            } catch (Exception e) {
+                System.out.println("exception thrown! " + e.getMessage());
+            }
+
+            gc();
+
+            double copBPS = -1;
+            try {
+                System.out.print("CompositeObjectPool\t" + ccg + "\t");
+                objectPool = ccg.getComposite();
+                copBPS = testForNumSeconds(seconds, objectPool);
+            } catch (Exception e) {
+                System.out.println("exception thrown! " + e.getMessage());
+            }
+
+            System.out.println("CompositeObjectPool/GenericObjectPool = " + (copBPS / gopBPS));
+
+            gc();
+        } while (ccg.nextSettings());
+    }
+
+    private double runThreadedTest(final ObjectPool pool, final int numThreads, final int seconds) {
+        final ThreadGroup threadGroup = new ThreadGroup("Testers");
+        final Thread[] threads = new Thread[numThreads];
+        final Borrower[] borrowers = new Borrower[threads.length];
+
+        long startTime = System.currentTimeMillis();
+        long actualEndTime;
+        synchronized (LOCK) {
+            for (int i=0; i < threads.length; i++) {
+                borrowers[i] = new Borrower(pool);
+                threads[i] = new Thread(threadGroup, borrowers[i]);
+                threads[i].start();
+            }
+            while (startTime == System.currentTimeMillis()) ;
+            startTime = System.currentTimeMillis();
+        }
+
+        try {
+            Thread.sleep(seconds * 1000);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        try {
+            pool.close();
+        } catch (Exception e) {
+            // ignored
+        }
+        actualEndTime = System.currentTimeMillis();
+
+        Thread.yield();
+        int loops = 0;
+        for (int i=0; i < threads.length; i++) {
+            if (threads[i].isAlive()) {
+                try {
+                    threads[i].join();
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+            }
+            loops += borrowers[i].getLoops();
+        }
+        final double borrowsPerSecond = ((double)loops / ((double)(actualEndTime - startTime) / 1000D));
+        System.out.println(borrowsPerSecond + " borrows per second");
+        return borrowsPerSecond;
+    }
+
+    private void compareThreadedCompositeGerneic(final int numThreads, final int seconds) {
+        final CompareCompositeGeneric ccg = new CompareCompositeGeneric();
+        do {
+            gc();
+
+            ObjectPool objectPool;
+            gc();
+
+            try {
+                System.out.print("GOP:noTestOnBorrow\t" + ccg + "\t");
+                objectPool = ccg.getGeneric();
+                ((GenericObjectPool)objectPool).setTestOnBorrow(false);
+                runThreadedTest(objectPool, numThreads, seconds);
+            } catch (Exception e) {
+                System.out.println("exception thrown! " + e.getMessage());
+            }
+
+            double gopBPS = -1;
+            try {
+                System.out.print("GenericObjectPool\t" + ccg + "\t");
+                objectPool = ccg.getGeneric();
+                ((GenericObjectPool)objectPool).setTestOnBorrow(true);
+                gopBPS = runThreadedTest(objectPool, numThreads, seconds);
+            } catch (Exception e) {
+                System.out.println("exception thrown! " + e.getMessage());
+            }
+
+            gc();
+
+            double copBPS = -1;
+            try {
+                System.out.print("CompositeObjectPool\t" + ccg + "\t");
+                objectPool = ccg.getComposite();
+                copBPS = runThreadedTest(objectPool, numThreads, seconds);
+            } catch (Exception e) {
+                System.out.println("exception thrown! " + e.getMessage());
+            }
+
+            System.out.println("CompositeObjectPool/GenericObjectPool = " + (copBPS / gopBPS));
+
+            gc();
+        } while (ccg.nextSettings());
+    }
+
+
+
+    public static void main(final String[] args) throws Exception {
+        System.out.println("Testing Class: " + PerformanceTest.class.getName());
+        PerformanceTest test = new PerformanceTest();
+
+        if (true) {
+            System.out.println("Single Threaded Test");
+            System.out.println("Warm up run (15): " + new Date());
+            test.compareCompositeGerneic(15);
+            //test.runEveryGeneric(20);
+            //test.runEveryComposite(20);
+            System.out.println("Go go go (60): " + new Date());
+            test.compareCompositeGerneic(60);
+            //test.runEveryGeneric(60);
+            //test.runEveryComposite(60);
+            System.out.println("Done: " + new Date());
+        }
+
+        if (false) {
+            int numThreads = 5;
+            System.out.println("Threaded Test: " + numThreads);
+            System.out.println("Warm up run (15): " + new Date());
+            test.compareThreadedCompositeGerneic(numThreads, 15);
+            System.out.println("Go go go (60): " + new Date());
+            test.compareThreadedCompositeGerneic(numThreads, 60);
+            System.out.println("Done: " + new Date());
+        }
+
+        if (false) {
+            System.out.println("List performances");
+            CompositeObjectPool cop;
+            System.out.print("ArrayList:w:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(1), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 1; i++) cop.addObject();
+            testForNumSeconds(25, cop);
+            gc();
+
+            System.out.print("LinkedList:w:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 1; i++) cop.addObject();
+            testForNumSeconds(25, cop);
+            gc();
+
+            System.out.print("ArrayList:1:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(1), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 1; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:1:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 1; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("ArrayList:2:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(2), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 2; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:2:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 2; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("ArrayList:3:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(3), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 3; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:3:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 3; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("ArrayList:5:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(5), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 5; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:5:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 5; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("ArrayList:10:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(10), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 10; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:10:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 10; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("ArrayList:25:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(25), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 25; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:25:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 25; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("ArrayList:50:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new ArrayList(50), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 50; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+            System.out.print("LinkedList:50:\t");
+            cop = new CompositeObjectPool(new IntegerFactory(), new LinkedList(), new GrowManager(), new FifoLender(), new SimpleTracker(), false, null);
+            for (int i=0; i < 50; i++) cop.addObject();
+            testForNumSeconds(60, cop);
+            gc();
+
+        }
+
+    }
+
+    private static class CompareCompositeGeneric {
+        private static final List maxIdles = Arrays.asList(new Integer[] {new Integer(-1), new Integer(10)});
+        private static final List maxActives = Arrays.asList(new Integer[] {new Integer(-1), new Integer(10)});
+        private static final List validateOnReturns = Arrays.asList(new Boolean[] {Boolean.FALSE, Boolean.TRUE});
+
+        private Iterator maxIdleIter = maxIdles.iterator();
+        private Iterator maxActiveIter = maxActives.iterator();
+        private Iterator validateIter = validateOnReturns.iterator();
+
+        private IntegerFactory objectFactory = new IntegerFactory();
+        private CompositeObjectPoolFactory compositeFactory = new CompositeObjectPoolFactory(objectFactory);
+        private GenericObjectPool.Config genericConfig = new GenericObjectPool.Config();
+
+        private Integer maxIdle;
+        private Integer maxActive;
+        private Boolean validateOnReturn;
+
+        public CompareCompositeGeneric() {
+            maxIdle = (Integer)maxIdleIter.next();
+            maxActive = (Integer)maxActiveIter.next();
+            validateOnReturn = (Boolean)validateIter.next();
+
+            compositeFactory.setBorrowType(BorrowType.FIFO);
+            compositeFactory.setExhaustionBehavior(ExhaustionBehavior.GROW);
+            compositeFactory.setLimitBehavior(LimitBehavior.FAIL);
+            compositeFactory.setTrackerType(TrackingType.SIMPLE);
+
+            genericConfig.minIdle = 0;
+            genericConfig.testOnBorrow = true;
+            genericConfig.testOnReturn = false;
+            genericConfig.whenExhaustedAction = GenericObjectPool.WHEN_EXHAUSTED_GROW;
+        }
+
+        public boolean nextSettings() {
+            boolean newCombination = true;
+            if (!validateIter.hasNext()) {
+                validateIter = validateOnReturns.iterator();
+
+                if (!maxActiveIter.hasNext()) {
+                    maxActiveIter = maxActives.iterator();
+
+                    if (!maxIdleIter.hasNext()) {
+                        maxIdleIter = maxIdles.iterator();
+                        newCombination = false;
+                    }
+                    maxIdle = (Integer)maxIdleIter.next();
+                }
+                maxActive = (Integer)maxActiveIter.next();
+            }
+            validateOnReturn = (Boolean)validateIter.next();
+
+            return newCombination;
+        }
+
+        public CompositeObjectPool getComposite() {
+            objectFactory.reset();
+            compositeFactory.setMaxActive(maxActive.intValue());
+            compositeFactory.setMaxIdle(maxIdle.intValue());
+            compositeFactory.setValidateOnReturn(validateOnReturn.booleanValue());
+            return (CompositeObjectPool)compositeFactory.createPool();
+        }
+
+        public GenericObjectPool getGeneric() {
+            objectFactory.reset();
+            genericConfig.maxActive = maxActive.intValue();
+            genericConfig.maxIdle = maxIdle.intValue();
+            genericConfig.testOnReturn = validateOnReturn.booleanValue();
+            return new GenericObjectPool(objectFactory, genericConfig);
+        }
+
+
+        public String toString() {
+            return '{' +
+                    "maxIdle=" + maxIdle +
+                    ", maxActive=" + maxActive +
+                    ", validateOnReturn=" + validateOnReturn +
+                    '}';
+        }
+    }
+    private static class IntegerFactory extends BasePoolableObjectFactory {
+        private int count = 0;
+        private boolean oddValid = true;
+        private boolean evenValid = true;
+
+        public Object makeObject() throws Exception {
+            return new Integer(count++);
+        }
+
+        public boolean validateObject(final Object obj) {
+            final Integer num = (Integer)obj;
+            if (num.intValue() % 2 == 0) {
+                return evenValid;
+            } else {
+                return oddValid;
+            }
+        }
+
+        public void setValid(final boolean valid) {
+            setEvenValid(valid);
+            setOddValid(valid);
+        }
+
+        public void setOddValid(final boolean oddValid) {
+            this.oddValid = oddValid;
+        }
+
+        public void setEvenValid(final boolean evenValid) {
+            this.evenValid = evenValid;
+        }
+
+        public void reset() {
+            count = 0;
+            oddValid = true;
+            evenValid = true;
+        }
+
+        public String toString() {
+            return "IntegerFactory{}";
+        }
+    }
+
+    private static class Borrower implements Runnable {
+        private final ObjectPool pool;
+        private int loops = 0;
+
+        public Borrower(final ObjectPool pool) {
+            this.pool = pool;
+        }
+
+        public void run() {
+            synchronized(LOCK) {
+                loops = 0;
+            }
+            while (true) {
+                try {
+                    final Object obj = pool.borrowObject();
+                    loops++;
+                    pool.returnObject(obj);
+                } catch (IllegalStateException ise) {
+                    return;
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        public int getLoops() {
+            return loops;
+        }
+    }
+}



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