commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rdon...@apache.org
Subject svn commit: r387630 [1/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...
Date Tue, 21 Mar 2006 21:41:57 GMT
Author: rdonkin
Date: Tue Mar 21 13:41:53 2006
New Revision: 387630

URL: http://svn.apache.org/viewcvs?rev=387630&view=rev
Log:
Initial drop of 'Composite implementation of Jakarta Commons Pool' donated by William A. McArthur, Jr. IP Clearance document: http://incubator.apache.org/ip-clearance/jakarta-commons-composite-pool.html. Unpacked from http://svn.apache.org/repos/asf/jakarta/grants/mcarthur-composite-pool.tar.

Added:
    jakarta/commons/proper/pool/contrib/composite-pool/java/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/AbstractLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/AbstractManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ActiveLimitManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/BorrowType.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPool.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPoolFactory.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPool.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPoolFactory.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/DebugTracker.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/DelegateLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/DelegateManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/EvictorLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ExhaustionBehavior.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/FailLimitManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/FailManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/FifoLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/GrowManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/IdleEvictorLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/IdleLimitManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/InvalidEvictorLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/KeyedPoolableObjectFactoryAdapter.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Lender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LifoLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/LimitBehavior.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Manager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/NullTracker.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/ReferenceTracker.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SimpleTracker.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/SoftLender.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/Tracker.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/TrackingType.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/WaitLimitManager.java
    jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/package.html
    jakarta/commons/proper/pool/contrib/composite-pool/test/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/PerformanceTest.java
    jakarta/commons/proper/pool/contrib/composite-pool/test/org/mcarthur/sandy/commons/pool/composite/TestCompositeObjectPool.java
Modified:
    jakarta/commons/proper/pool/contrib/composite-pool/   (props changed)

Propchange: jakarta/commons/proper/pool/contrib/composite-pool/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Mar 21 13:41:53 2006
@@ -0,0 +1 @@
+.*

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

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

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

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

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPool.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPool.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPool.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,480 @@
+/*
+ * 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.
+ *
+ * <p>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.</p>
+ *
+ * @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 the <code>key</code>.
+     *
+     * @param key which object pool to get or create.
+     * @return the object pool for <code>key</code>.
+     */
+    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 <i>key</i>.
+     * By contract, clients MUST return
+     * the borrowed object using
+     * {@link #returnObject(Object,Object) <tt>returnObject</tt>},
+     * or a related method as defined in an implementation
+     * or sub-interface,
+     * using a <i>key</i> 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, <i>obj</i> MUST have been obtained
+     * using {@link #borrowObject(Object) <tt>borrowObject</tt>}
+     * or a related method as defined in an implementation
+     * or sub-interface
+     * using a <i>key</i> that is equivalent to the one used to
+     * borrow the <tt>Object</tt> 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, <i>obj</i> MUST have been obtained
+     * using {@link #borrowObject borrowObject}
+     * or a related method as defined in an implementation
+     * or sub-interface
+     * using a <i>key</i> that is equivalent to the one used to
+     * borrow the <tt>Object</tt> in the first place.
+     * <p>
+     * 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 <i>key</i>
+     * 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 <i>key</i> 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 <i>key</i> (optional operation).
+     * Throws {@link UnsupportedOperationException}
+     * if this information is not available.
+     *
+     * @param key the key
+     * @return the number of instances corresponding to the given <i>key</i> 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 <i>key</i>  (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;
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPoolFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPoolFactory.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPoolFactory.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeKeyedObjectPoolFactory.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,422 @@
+/*
+ * 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.
+ *
+ * <p>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}.
+ * </p>
+ *
+ * @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 if <code>factory</code> is <code>null</code>.
+     * @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 <code>factory</code> is <code>null</code>.
+     * @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 <code>factory</code> is <code>null</code>.
+     */
+    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.
+     *
+     * <p><b>There are no guarentees the {@link KeyedObjectPool} returned by this method will behave in previously
+     * guarenteed way. Use at your own risk.</b></p>
+     *
+     * @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 if <code>factory</code> is <code>null</code>.
+     */
+    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 <code>factory</code> is <code>null</code>.
+     * @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 <code>factory</code> is <code>null</code>.
+     * @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 <code>borrowType</code> is <code>null</code>.
+     */
+    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 <code>exhaustionBehavior</code> is <code>null</code>.
+     */
+    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 &gt; 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 &lt;= 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 <code>limitBehavior</code> is <code>null</code>.
+     * @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 &lt;= 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 <code>trackerType</code> is <code>null</code>.
+     */
+    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 <code>true</code> 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);
+    }
+}
\ No newline at end of file

Added: jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPool.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPool.java?rev=387630&view=auto
==============================================================================
--- jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPool.java (added)
+++ jakarta/commons/proper/pool/contrib/composite-pool/java/org/mcarthur/sandy/commons/pool/composite/CompositeObjectPool.java Tue Mar 21 13:41:53 2006
@@ -0,0 +1,427 @@
+/*
+ * 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.
+ *
+ * <p>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.</p>
+ *
+ * <p>Composit object pools are divided into three parts.</p>
+ *
+ * <p>{@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.
+ * </p>
+ *
+ * <p>{@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.</p>
+ *
+ * <p>{@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.</p>
+ *
+ * @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.
+     * <p/>
+     * 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, <i>obj</i> 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, <i>obj</i> MUST have been obtained
+     * using {@link #borrowObject() borrowObject}
+     * or a related method as defined in an implementation
+     * or sub-interface.
+     * <p/>
+     * 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}.
+     * @return <code>false</code> 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);
+    }
+}
\ No newline at end of file



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


Mime
View raw message