All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.pool.PoolUtils Maven / Gradle / Ivy

There is a newer version: 4.0.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.commons.pool;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Collections;

/**
 * This class consists exclusively of static methods that operate on or return ObjectPool
 * or KeyedObjectPool related interfaces.
 *
 * @author Sandy McArthur
 * @version $Revision: 777748 $ $Date: 2009-05-22 20:00:44 -0400 (Fri, 22 May 2009) $
 * @since Pool 1.3
 */
public final class PoolUtils {

    /**
     * Timer used to periodically check pools idle object count.
     * Because a {@link Timer} creates a {@link Thread} this is lazily instantiated.
     */
    private static Timer MIN_IDLE_TIMER;

    /**
     * PoolUtils instances should NOT be constructed in standard programming.
     * Instead, the class should be used procedurally: PoolUtils.adapt(aPool);.
     * This constructor is public to permit tools that require a JavaBean instance to operate.
     */
    public PoolUtils() {
    }

    /**
     * Adapt a KeyedPoolableObjectFactory instance to work where a PoolableObjectFactory is
     * needed. This method is the equivalent of calling
     * {@link #adapt(KeyedPoolableObjectFactory, Object) PoolUtils.adapt(aKeyedPoolableObjectFactory, new Object())}.
     *
     * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
     * @return a {@link PoolableObjectFactory} that delegates to keyedFactory with an internal key.
     * @throws IllegalArgumentException when keyedFactory is null.
     * @see #adapt(KeyedPoolableObjectFactory, Object)
     * @since Pool 1.3
     */
    public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException {
        return adapt(keyedFactory, new Object());
    }

    /**
     * Adapt a KeyedPoolableObjectFactory instance to work where a PoolableObjectFactory is
     * needed using the specified key when delegating.
     *
     * @param keyedFactory the {@link KeyedPoolableObjectFactory} to delegate to.
     * @param key the key to use when delegating.
     * @return a {@link PoolableObjectFactory} that delegates to keyedFactory with the specified key.
     * @throws IllegalArgumentException when keyedFactory or key is null.
     * @see #adapt(KeyedPoolableObjectFactory)
     * @since Pool 1.3
     */
    public static PoolableObjectFactory adapt(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException {
        return new PoolableObjectFactoryAdaptor(keyedFactory, key);
    }

    /**
     * Adapt a PoolableObjectFactory instance to work where a KeyedPoolableObjectFactory is
     * needed. The key is ignored.
     *
     * @param factory the {@link PoolableObjectFactory} to delegate to.
     * @return a {@link KeyedPoolableObjectFactory} that delegates to factory ignoring the key.
     * @throws IllegalArgumentException when factory is null.
     * @since Pool 1.3
     */
    public static KeyedPoolableObjectFactory adapt(final PoolableObjectFactory factory) throws IllegalArgumentException {
        return new KeyedPoolableObjectFactoryAdaptor(factory);
    }

    /**
     * Adapt a KeyedObjectPool instance to work where an ObjectPool is needed. This is the
     * equivalent of calling {@link #adapt(KeyedObjectPool, Object) PoolUtils.adapt(aKeyedObjectPool, new Object())}.
     *
     * @param keyedPool the {@link KeyedObjectPool} to delegate to.
     * @return an {@link ObjectPool} that delegates to keyedPool with an internal key.
     * @throws IllegalArgumentException when keyedPool is null.
     * @see #adapt(KeyedObjectPool, Object)
     * @since Pool 1.3
     */
    public static ObjectPool adapt(final KeyedObjectPool keyedPool) throws IllegalArgumentException {
        return adapt(keyedPool, new Object());
    }

    /**
     * Adapt a KeyedObjectPool instance to work where an ObjectPool is needed using the
     * specified key when delegating.
     *
     * @param keyedPool the {@link KeyedObjectPool} to delegate to.
     * @param key the key to use when delegating.
     * @return an {@link ObjectPool} that delegates to keyedPool with the specified key.
     * @throws IllegalArgumentException when keyedPool or key is null.
     * @see #adapt(KeyedObjectPool)
     * @since Pool 1.3
     */
    public static ObjectPool adapt(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException {
        return new ObjectPoolAdaptor(keyedPool, key);
    }

    /**
     * Adapt an ObjectPool to work where an KeyedObjectPool is needed.
     * The key is ignored.
     *
     * @param pool the {@link ObjectPool} to delegate to.
     * @return a {@link KeyedObjectPool} that delegates to pool ignoring the key.
     * @throws IllegalArgumentException when pool is null.
     * @since Pool 1.3
     */
    public static KeyedObjectPool adapt(final ObjectPool pool) throws IllegalArgumentException {
        return new KeyedObjectPoolAdaptor(pool);
    }

    /**
     * Wraps an ObjectPool and dynamically checks the type of objects borrowed and returned to the pool.
     * If an object is passed to the pool that isn't of type type a {@link ClassCastException} will be thrown.
     *
     * @param pool the pool to enforce type safety on
     * @param type the class type to enforce.
     * @return an ObjectPool that will only allow objects of type
     * @since Pool 1.3
     */
    public static ObjectPool checkedPool(final ObjectPool pool, final Class type) {
        if (pool == null) {
            throw new IllegalArgumentException("pool must not be null.");
        }
        if (type == null) {
            throw new IllegalArgumentException("type must not be null.");
        }
        return new CheckedObjectPool(pool, type);
    }

    /**
     * Wraps a KeyedObjectPool and dynamically checks the type of objects borrowed and returned to the keyedPool.
     * If an object is passed to the keyedPool that isn't of type type a {@link ClassCastException} will be thrown.
     *
     * @param keyedPool the keyedPool to enforce type safety on
     * @param type the class type to enforce.
     * @return a KeyedObjectPool that will only allow objects of type
     * @since Pool 1.3
     */
    public static KeyedObjectPool checkedPool(final KeyedObjectPool keyedPool, final Class type) {
        if (keyedPool == null) {
            throw new IllegalArgumentException("keyedPool must not be null.");
        }
        if (type == null) {
            throw new IllegalArgumentException("type must not be null.");
        }
        return new CheckedKeyedObjectPool(keyedPool, type);
    }

    /**
     * Periodically check the idle object count for the pool. At most one idle object will be added per period.
     * If there is an exception when calling {@link ObjectPool#addObject()} then no more checks will be performed.
     *
     * @param pool the pool to check periodically.
     * @param minIdle if the {@link ObjectPool#getNumIdle()} is less than this then add an idle object.
     * @param period the frequency to check the number of idle objects in a pool, see
     *      {@link Timer#schedule(TimerTask, long, long)}.
     * @return the {@link TimerTask} that will periodically check the pools idle object count.
     * @throws IllegalArgumentException when pool is null or
     *      when minIdle is negative or when period isn't
     *      valid for {@link Timer#schedule(TimerTask, long, long)}.
     * @since Pool 1.3
     */
    public static TimerTask checkMinIdle(final ObjectPool pool, final int minIdle, final long period) throws IllegalArgumentException {
        if (pool == null) {
            throw new IllegalArgumentException("keyedPool must not be null.");
        }
        if (minIdle < 0) {
            throw new IllegalArgumentException("minIdle must be non-negative.");
        }
        final TimerTask task = new ObjectPoolMinIdleTimerTask(pool, minIdle);
        getMinIdleTimer().schedule(task, 0L, period);
        return task;
    }

    /**
     * Periodically check the idle object count for the key in the keyedPool. At most one idle object will be added per period.
     * If there is an exception when calling {@link KeyedObjectPool#addObject(Object)} then no more checks for that key
     * will be performed.
     *
     * @param keyedPool the keyedPool to check periodically.
     * @param key the key to check the idle count of.
     * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
     * @param period the frequency to check the number of idle objects in a keyedPool, see
     *      {@link Timer#schedule(TimerTask, long, long)}.
     * @return the {@link TimerTask} that will periodically check the pools idle object count.
     * @throws IllegalArgumentException when keyedPool, key is null or
     *      when minIdle is negative or when period isn't
     *      valid for {@link Timer#schedule(TimerTask, long, long)}.
     * @since Pool 1.3
     */
    public static TimerTask checkMinIdle(final KeyedObjectPool keyedPool, final Object key, final int minIdle, final long period) throws IllegalArgumentException {
        if (keyedPool == null) {
            throw new IllegalArgumentException("keyedPool must not be null.");
        }
        if (key == null) {
            throw new IllegalArgumentException("key must not be null.");
        }
        if (minIdle < 0) {
            throw new IllegalArgumentException("minIdle must be non-negative.");
        }
        final TimerTask task = new KeyedObjectPoolMinIdleTimerTask(keyedPool, key, minIdle);
        getMinIdleTimer().schedule(task, 0L, period);
        return task;
    }

    /**
     * Periodically check the idle object count for each key in the Collection keys in the keyedPool.
     * At most one idle object will be added per period.
     *
     * @param keyedPool the keyedPool to check periodically.
     * @param keys a collection of keys to check the idle object count.
     * @param minIdle if the {@link KeyedObjectPool#getNumIdle(Object)} is less than this then add an idle object.
     * @param period the frequency to check the number of idle objects in a keyedPool, see
     *      {@link Timer#schedule(TimerTask, long, long)}.
     * @return a {@link Map} of key and {@link TimerTask} pairs that will periodically check the pools idle object count.
     * @throws IllegalArgumentException when keyedPool, keys, or any of the values in the
     *      collection is null or when minIdle is negative or when period isn't
     *      valid for {@link Timer#schedule(TimerTask, long, long)}.
     * @see #checkMinIdle(KeyedObjectPool, Object, int, long)
     * @since Pool 1.3
     */
    public static Map checkMinIdle(final KeyedObjectPool keyedPool, final Collection keys, final int minIdle, final long period) throws IllegalArgumentException {
        if (keys == null) {
            throw new IllegalArgumentException("keys must not be null.");
        }
        final Map tasks = new HashMap(keys.size());
        final Iterator iter = keys.iterator();
        while (iter.hasNext()) {
            final Object key = iter.next();
            final TimerTask task = checkMinIdle(keyedPool, key, minIdle, period);
            tasks.put(key, task);
        }
        return tasks;
    }

    /**
     * Call addObject() on pool count number of times.
     *
     * @param pool the pool to prefill.
     * @param count the number of idle objects to add.
     * @throws Exception when {@link ObjectPool#addObject()} fails.
     * @throws IllegalArgumentException when pool is null.
     * @since Pool 1.3
     */
    public static void prefill(final ObjectPool pool, final int count) throws Exception, IllegalArgumentException {
        if (pool == null) {
            throw new IllegalArgumentException("pool must not be null.");
        }
        for (int i = 0; i < count; i++) {
            pool.addObject();
        }
    }

    /**
     * Call addObject(Object) on keyedPool with key count
     * number of times.
     *
     * @param keyedPool the keyedPool to prefill.
     * @param key the key to add objects for.
     * @param count the number of idle objects to add for key.
     * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
     * @throws IllegalArgumentException when keyedPool or key is null.
     * @since Pool 1.3
     */
    public static void prefill(final KeyedObjectPool keyedPool, final Object key, final int count) throws Exception, IllegalArgumentException {
        if (keyedPool == null) {
            throw new IllegalArgumentException("keyedPool must not be null.");
        }
        if (key == null) {
            throw new IllegalArgumentException("key must not be null.");
        }
        for (int i = 0; i < count; i++) {
            keyedPool.addObject(key);
        }
    }

    /**
     * Call addObject(Object) on keyedPool with each key in keys for
     * count number of times. This has the same effect as calling
     * {@link #prefill(KeyedObjectPool, Object, int)} for each key in the keys collection.
     *
     * @param keyedPool the keyedPool to prefill.
     * @param keys {@link Collection} of keys to add objects for.
     * @param count the number of idle objects to add for each key.
     * @throws Exception when {@link KeyedObjectPool#addObject(Object)} fails.
     * @throws IllegalArgumentException when keyedPool, keys, or
     *      any value in keys is null.
     * @see #prefill(KeyedObjectPool, Object, int)
     * @since Pool 1.3
     */
    public static void prefill(final KeyedObjectPool keyedPool, final Collection keys, final int count) throws Exception, IllegalArgumentException {
        if (keys == null) {
            throw new IllegalArgumentException("keys must not be null.");
        }
        final Iterator iter = keys.iterator();
        while (iter.hasNext()) {
            prefill(keyedPool, iter.next(), count);
        }
    }

    /**
     * Returns a synchronized (thread-safe) ObjectPool backed by the specified ObjectPool.
     *
     * 

Note: * This should not be used on pool implementations that already provide proper synchronization * such as the pools provided in the Commons Pool library. Wrapping a pool that * {@link #wait() waits} for poolable objects to be returned before allowing another one to be * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. *

* * @param pool the ObjectPool to be "wrapped" in a synchronized ObjectPool. * @return a synchronized view of the specified ObjectPool. * @since Pool 1.3 */ public static ObjectPool synchronizedPool(final ObjectPool pool) { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); } /* assert !(pool instanceof GenericObjectPool) : "GenericObjectPool is already thread-safe"; assert !(pool instanceof SoftReferenceObjectPool) : "SoftReferenceObjectPool is already thread-safe"; assert !(pool instanceof StackObjectPool) : "StackObjectPool is already thread-safe"; assert !"org.apache.commons.pool.composite.CompositeObjectPool".equals(pool.getClass().getName()) : "CompositeObjectPools are already thread-safe"; */ return new SynchronizedObjectPool(pool); } /** * Returns a synchronized (thread-safe) KeyedObjectPool backed by the specified KeyedObjectPool. * *

Note: * This should not be used on pool implementations that already provide proper synchronization * such as the pools provided in the Commons Pool library. Wrapping a pool that * {@link #wait() waits} for poolable objects to be returned before allowing another one to be * borrowed with another layer of synchronization will cause liveliness issues or a deadlock. *

* * @param keyedPool the KeyedObjectPool to be "wrapped" in a synchronized KeyedObjectPool. * @return a synchronized view of the specified KeyedObjectPool. * @since Pool 1.3 */ public static KeyedObjectPool synchronizedPool(final KeyedObjectPool keyedPool) { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } /* assert !(keyedPool instanceof GenericKeyedObjectPool) : "GenericKeyedObjectPool is already thread-safe"; assert !(keyedPool instanceof StackKeyedObjectPool) : "StackKeyedObjectPool is already thread-safe"; assert !"org.apache.commons.pool.composite.CompositeKeyedObjectPool".equals(keyedPool.getClass().getName()) : "CompositeKeyedObjectPools are already thread-safe"; */ return new SynchronizedKeyedObjectPool(keyedPool); } /** * Returns a synchronized (thread-safe) PoolableObjectFactory backed by the specified PoolableObjectFactory. * * @param factory the PoolableObjectFactory to be "wrapped" in a synchronized PoolableObjectFactory. * @return a synchronized view of the specified PoolableObjectFactory. * @since Pool 1.3 */ public static PoolableObjectFactory synchronizedPoolableFactory(final PoolableObjectFactory factory) { return new SynchronizedPoolableObjectFactory(factory); } /** * Returns a synchronized (thread-safe) KeyedPoolableObjectFactory backed by the specified KeyedPoolableObjectFactory. * * @param keyedFactory the KeyedPoolableObjectFactory to be "wrapped" in a synchronized KeyedPoolableObjectFactory. * @return a synchronized view of the specified KeyedPoolableObjectFactory. * @since Pool 1.3 */ public static KeyedPoolableObjectFactory synchronizedPoolableFactory(final KeyedPoolableObjectFactory keyedFactory) { return new SynchronizedKeyedPoolableObjectFactory(keyedFactory); } /** * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. * This is intended as an always thread-safe alternative to using an idle object evictor * provided by many pool implementations. This is also an effective way to shrink FIFO ordered * pools that experience load spikes. * * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible. * @return a pool that adaptively decreases it's size when idle objects are no longer needed. * @see #erodingPool(ObjectPool, float) * @since Pool 1.4 */ public static ObjectPool erodingPool(final ObjectPool pool) { return erodingPool(pool, 1f); } /** * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. * This is intended as an always thread-safe alternative to using an idle object evictor * provided by many pool implementations. This is also an effective way to shrink FIFO ordered * pools that experience load spikes. * *

* The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. * Values greater than 1 cause the pool to less frequently try to shrink it's size. *

* * @param pool the ObjectPool to be decorated so it shrinks it's idle count when possible. * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. * If 0 < factor < 1 then the pool shrinks more aggressively. * If 1 < factor then the pool shrinks less aggressively. * @return a pool that adaptively decreases it's size when idle objects are no longer needed. * @see #erodingPool(ObjectPool) * @since Pool 1.4 */ public static ObjectPool erodingPool(final ObjectPool pool, final float factor) { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); } if (factor <= 0f) { throw new IllegalArgumentException("factor must be positive."); } return new ErodingObjectPool(pool, factor); } /** * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. * This is intended as an always thread-safe alternative to using an idle object evictor * provided by many pool implementations. This is also an effective way to shrink FIFO ordered * pools that experience load spikes. * * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when * possible. * @return a pool that adaptively decreases it's size when idle objects are no longer needed. * @see #erodingPool(KeyedObjectPool, float) * @see #erodingPool(KeyedObjectPool, float, boolean) * @since Pool 1.4 */ public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool) { return erodingPool(keyedPool, 1f); } /** * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. * This is intended as an always thread-safe alternative to using an idle object evictor * provided by many pool implementations. This is also an effective way to shrink FIFO ordered * pools that experience load spikes. * *

* The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. * Values greater than 1 cause the pool to less frequently try to shrink it's size. *

* * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when * possible. * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. * If 0 < factor < 1 then the pool shrinks more aggressively. * If 1 < factor then the pool shrinks less aggressively. * @return a pool that adaptively decreases it's size when idle objects are no longer needed. * @see #erodingPool(KeyedObjectPool, float, boolean) * @since Pool 1.4 */ public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor) { return erodingPool(keyedPool, factor, false); } /** * Returns a pool that adaptively decreases it's size when idle objects are no longer needed. * This is intended as an always thread-safe alternative to using an idle object evictor * provided by many pool implementations. This is also an effective way to shrink FIFO ordered * pools that experience load spikes. * *

* The factor parameter provides a mechanism to tweak the rate at which the pool tries to shrink * it's size. Values between 0 and 1 cause the pool to try to shrink it's size more often. * Values greater than 1 cause the pool to less frequently try to shrink it's size. *

* *

* The perKey parameter determines if the pool shrinks on a whole pool basis or a per key basis. * When perKey is false, the keys do not have an effect on the rate at which the pool tries to * shrink it's size. When perKey is true, each key is shrunk independently. *

* * @param keyedPool the KeyedObjectPool to be decorated so it shrinks it's idle count when * possible. * @param factor a positive value to scale the rate at which the pool tries to reduce it's size. * If 0 < factor < 1 then the pool shrinks more aggressively. * If 1 < factor then the pool shrinks less aggressively. * @param perKey when true, each key is treated independently. * @return a pool that adaptively decreases it's size when idle objects are no longer needed. * @see #erodingPool(KeyedObjectPool) * @see #erodingPool(KeyedObjectPool, float) * @since Pool 1.4 */ public static KeyedObjectPool erodingPool(final KeyedObjectPool keyedPool, final float factor, final boolean perKey) { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } if (factor <= 0f) { throw new IllegalArgumentException("factor must be positive."); } if (perKey) { return new ErodingPerKeyKeyedObjectPool(keyedPool, factor); } else { return new ErodingKeyedObjectPool(keyedPool, factor); } } /** * Get the Timer for checking keyedPool's idle count. Lazily create the {@link Timer} as needed. * * @return the {@link Timer} for checking keyedPool's idle count. * @since Pool 1.3 */ private static synchronized Timer getMinIdleTimer() { if (MIN_IDLE_TIMER == null) { MIN_IDLE_TIMER = new Timer(true); } return MIN_IDLE_TIMER; } private static class PoolableObjectFactoryAdaptor implements PoolableObjectFactory { private final Object key; private final KeyedPoolableObjectFactory keyedFactory; PoolableObjectFactoryAdaptor(final KeyedPoolableObjectFactory keyedFactory, final Object key) throws IllegalArgumentException { if (keyedFactory == null) { throw new IllegalArgumentException("keyedFactory must not be null."); } if (key == null) { throw new IllegalArgumentException("key must not be null."); } this.keyedFactory = keyedFactory; this.key = key; } public Object makeObject() throws Exception { return keyedFactory.makeObject(key); } public void destroyObject(final Object obj) throws Exception { keyedFactory.destroyObject(key, obj); } public boolean validateObject(final Object obj) { return keyedFactory.validateObject(key, obj); } public void activateObject(final Object obj) throws Exception { keyedFactory.activateObject(key, obj); } public void passivateObject(final Object obj) throws Exception { keyedFactory.passivateObject(key, obj); } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("PoolableObjectFactoryAdaptor"); sb.append("{key=").append(key); sb.append(", keyedFactory=").append(keyedFactory); sb.append('}'); return sb.toString(); } } private static class KeyedPoolableObjectFactoryAdaptor implements KeyedPoolableObjectFactory { private final PoolableObjectFactory factory; KeyedPoolableObjectFactoryAdaptor(final PoolableObjectFactory factory) throws IllegalArgumentException { if (factory == null) { throw new IllegalArgumentException("factory must not be null."); } this.factory = factory; } public Object makeObject(final Object key) throws Exception { return factory.makeObject(); } public void destroyObject(final Object key, final Object obj) throws Exception { factory.destroyObject(obj); } public boolean validateObject(final Object key, final Object obj) { return factory.validateObject(obj); } public void activateObject(final Object key, final Object obj) throws Exception { factory.activateObject(obj); } public void passivateObject(final Object key, final Object obj) throws Exception { factory.passivateObject(obj); } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("KeyedPoolableObjectFactoryAdaptor"); sb.append("{factory=").append(factory); sb.append('}'); return sb.toString(); } } private static class ObjectPoolAdaptor implements ObjectPool { private final Object key; private final KeyedObjectPool keyedPool; ObjectPoolAdaptor(final KeyedObjectPool keyedPool, final Object key) throws IllegalArgumentException { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } if (key == null) { throw new IllegalArgumentException("key must not be null."); } this.keyedPool = keyedPool; this.key = key; } public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { return keyedPool.borrowObject(key); } public void returnObject(final Object obj) { try { keyedPool.returnObject(key, obj); } catch (Exception e) { // swallowed as of Pool 2 } } public void invalidateObject(final Object obj) { try { keyedPool.invalidateObject(key, obj); } catch (Exception e) { // swallowed as of Pool 2 } } public void addObject() throws Exception, IllegalStateException { keyedPool.addObject(key); } public int getNumIdle() throws UnsupportedOperationException { return keyedPool.getNumIdle(key); } public int getNumActive() throws UnsupportedOperationException { return keyedPool.getNumActive(key); } public void clear() throws Exception, UnsupportedOperationException { keyedPool.clear(); } public void close() { try { keyedPool.close(); } catch (Exception e) { // swallowed as of Pool 2 } } public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { keyedPool.setFactory(adapt(factory)); } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("ObjectPoolAdaptor"); sb.append("{key=").append(key); sb.append(", keyedPool=").append(keyedPool); sb.append('}'); return sb.toString(); } } private static class KeyedObjectPoolAdaptor implements KeyedObjectPool { private final ObjectPool pool; KeyedObjectPoolAdaptor(final ObjectPool pool) throws IllegalArgumentException { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); } this.pool = pool; } public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { return pool.borrowObject(); } public void returnObject(final Object key, final Object obj) { try { pool.returnObject(obj); } catch (Exception e) { // swallowed as of Pool 2 } } public void invalidateObject(final Object key, final Object obj) { try { pool.invalidateObject(obj); } catch (Exception e) { // swallowed as of Pool 2 } } public void addObject(final Object key) throws Exception, IllegalStateException { pool.addObject(); } public int getNumIdle(final Object key) throws UnsupportedOperationException { return pool.getNumIdle(); } public int getNumActive(final Object key) throws UnsupportedOperationException { return pool.getNumActive(); } public int getNumIdle() throws UnsupportedOperationException { return pool.getNumIdle(); } public int getNumActive() throws UnsupportedOperationException { return pool.getNumActive(); } public void clear() throws Exception, UnsupportedOperationException { pool.clear(); } public void clear(final Object key) throws Exception, UnsupportedOperationException { pool.clear(); } public void close() { try { pool.close(); } catch (Exception e) { // swallowed as of Pool 2 } } public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { pool.setFactory(adapt(factory)); } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("KeyedObjectPoolAdaptor"); sb.append("{pool=").append(pool); sb.append('}'); return sb.toString(); } } private static class CheckedObjectPool implements ObjectPool { private final Class type; private final ObjectPool pool; CheckedObjectPool(final ObjectPool pool, final Class type) { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); } if (type == null) { throw new IllegalArgumentException("type must not be null."); } this.pool = pool; this.type = type; } public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { final Object obj = pool.borrowObject(); if (type.isInstance(obj)) { return obj; } else { throw new ClassCastException("Borrowed object is not of type: " + type.getName() + " was: " + obj); } } public void returnObject(final Object obj) { if (type.isInstance(obj)) { try { pool.returnObject(obj); } catch (Exception e) { // swallowed as of Pool 2 } } else { throw new ClassCastException("Returned object is not of type: " + type.getName() + " was: " + obj); } } public void invalidateObject(final Object obj) { if (type.isInstance(obj)) { try { pool.invalidateObject(obj); } catch (Exception e) { // swallowed as of Pool 2 } } else { throw new ClassCastException("Invalidated object is not of type: " + type.getName() + " was: " + obj); } } public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { pool.addObject(); } public int getNumIdle() throws UnsupportedOperationException { return pool.getNumIdle(); } public int getNumActive() throws UnsupportedOperationException { return pool.getNumActive(); } public void clear() throws Exception, UnsupportedOperationException { pool.clear(); } public void close() { try { pool.close(); } catch (Exception e) { // swallowed as of Pool 2 } } public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { pool.setFactory(factory); } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("CheckedObjectPool"); sb.append("{type=").append(type); sb.append(", pool=").append(pool); sb.append('}'); return sb.toString(); } } private static class CheckedKeyedObjectPool implements KeyedObjectPool { private final Class type; private final KeyedObjectPool keyedPool; CheckedKeyedObjectPool(final KeyedObjectPool keyedPool, final Class type) { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } if (type == null) { throw new IllegalArgumentException("type must not be null."); } this.keyedPool = keyedPool; this.type = type; } public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { Object obj = keyedPool.borrowObject(key); if (type.isInstance(obj)) { return obj; } else { throw new ClassCastException("Borrowed object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); } } public void returnObject(final Object key, final Object obj) { if (type.isInstance(obj)) { try { keyedPool.returnObject(key, obj); } catch (Exception e) { // swallowed as of Pool 2 } } else { throw new ClassCastException("Returned object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); } } public void invalidateObject(final Object key, final Object obj) { if (type.isInstance(obj)) { try { keyedPool.invalidateObject(key, obj); } catch (Exception e) { // swallowed as of Pool 2 } } else { throw new ClassCastException("Invalidated object for key: " + key + " is not of type: " + type.getName() + " was: " + obj); } } public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { keyedPool.addObject(key); } public int getNumIdle(final Object key) throws UnsupportedOperationException { return keyedPool.getNumIdle(key); } public int getNumActive(final Object key) throws UnsupportedOperationException { return keyedPool.getNumActive(key); } public int getNumIdle() throws UnsupportedOperationException { return keyedPool.getNumIdle(); } public int getNumActive() throws UnsupportedOperationException { return keyedPool.getNumActive(); } public void clear() throws Exception, UnsupportedOperationException { keyedPool.clear(); } public void clear(final Object key) throws Exception, UnsupportedOperationException { keyedPool.clear(key); } public void close() { try { keyedPool.close(); } catch (Exception e) { // swallowed as of Pool 2 } } public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { keyedPool.setFactory(factory); } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("CheckedKeyedObjectPool"); sb.append("{type=").append(type); sb.append(", keyedPool=").append(keyedPool); sb.append('}'); return sb.toString(); } } private static class ObjectPoolMinIdleTimerTask extends TimerTask { private final int minIdle; private final ObjectPool pool; ObjectPoolMinIdleTimerTask(final ObjectPool pool, final int minIdle) throws IllegalArgumentException { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); } this.pool = pool; this.minIdle = minIdle; } public void run() { boolean success = false; try { if (pool.getNumIdle() < minIdle) { pool.addObject(); } success = true; } catch (Exception e) { cancel(); } finally { // detect other types of Throwable and cancel this Timer if (!success) { cancel(); } } } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("ObjectPoolMinIdleTimerTask"); sb.append("{minIdle=").append(minIdle); sb.append(", pool=").append(pool); sb.append('}'); return sb.toString(); } } private static class KeyedObjectPoolMinIdleTimerTask extends TimerTask { private final int minIdle; private final Object key; private final KeyedObjectPool keyedPool; KeyedObjectPoolMinIdleTimerTask(final KeyedObjectPool keyedPool, final Object key, final int minIdle) throws IllegalArgumentException { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } this.keyedPool = keyedPool; this.key = key; this.minIdle = minIdle; } public void run() { boolean success = false; try { if (keyedPool.getNumIdle(key) < minIdle) { keyedPool.addObject(key); } success = true; } catch (Exception e) { cancel(); } finally { // detect other types of Throwable and cancel this Timer if (!success) { cancel(); } } } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("KeyedObjectPoolMinIdleTimerTask"); sb.append("{minIdle=").append(minIdle); sb.append(", key=").append(key); sb.append(", keyedPool=").append(keyedPool); sb.append('}'); return sb.toString(); } } private static class SynchronizedObjectPool implements ObjectPool { private final Object lock; private final ObjectPool pool; SynchronizedObjectPool(final ObjectPool pool) throws IllegalArgumentException { if (pool == null) { throw new IllegalArgumentException("pool must not be null."); } this.pool = pool; lock = new Object(); } public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { synchronized (lock) { return pool.borrowObject(); } } public void returnObject(final Object obj) { synchronized (lock) { try { pool.returnObject(obj); } catch (Exception e) { // swallowed as of Pool 2 } } } public void invalidateObject(final Object obj) { synchronized (lock) { try { pool.invalidateObject(obj); } catch (Exception e) { // swallowed as of Pool 2 } } } public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { synchronized (lock) { pool.addObject(); } } public int getNumIdle() throws UnsupportedOperationException { synchronized (lock) { return pool.getNumIdle(); } } public int getNumActive() throws UnsupportedOperationException { synchronized (lock) { return pool.getNumActive(); } } public void clear() throws Exception, UnsupportedOperationException { synchronized (lock) { pool.clear(); } } public void close() { try { synchronized (lock) { pool.close(); } } catch (Exception e) { // swallowed as of Pool 2 } } public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { synchronized (lock) { pool.setFactory(factory); } } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedObjectPool"); sb.append("{pool=").append(pool); sb.append('}'); return sb.toString(); } } private static class SynchronizedKeyedObjectPool implements KeyedObjectPool { private final Object lock; private final KeyedObjectPool keyedPool; SynchronizedKeyedObjectPool(final KeyedObjectPool keyedPool) throws IllegalArgumentException { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } this.keyedPool = keyedPool; lock = new Object(); } public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { synchronized (lock) { return keyedPool.borrowObject(key); } } public void returnObject(final Object key, final Object obj) { synchronized (lock) { try { keyedPool.returnObject(key, obj); } catch (Exception e) { // swallowed } } } public void invalidateObject(final Object key, final Object obj) { synchronized (lock) { try { keyedPool.invalidateObject(key, obj); } catch (Exception e) { // swallowed as of Pool 2 } } } public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { synchronized (lock) { keyedPool.addObject(key); } } public int getNumIdle(final Object key) throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumIdle(key); } } public int getNumActive(final Object key) throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumActive(key); } } public int getNumIdle() throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumIdle(); } } public int getNumActive() throws UnsupportedOperationException { synchronized (lock) { return keyedPool.getNumActive(); } } public void clear() throws Exception, UnsupportedOperationException { synchronized (lock) { keyedPool.clear(); } } public void clear(final Object key) throws Exception, UnsupportedOperationException { synchronized (lock) { keyedPool.clear(key); } } public void close() { try { synchronized (lock) { keyedPool.close(); } } catch (Exception e) { // swallowed as of Pool 2 } } public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { synchronized (lock) { keyedPool.setFactory(factory); } } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedKeyedObjectPool"); sb.append("{keyedPool=").append(keyedPool); sb.append('}'); return sb.toString(); } } private static class SynchronizedPoolableObjectFactory implements PoolableObjectFactory { private final Object lock; private final PoolableObjectFactory factory; SynchronizedPoolableObjectFactory(final PoolableObjectFactory factory) throws IllegalArgumentException { if (factory == null) { throw new IllegalArgumentException("factory must not be null."); } this.factory = factory; lock = new Object(); } public Object makeObject() throws Exception { synchronized (lock) { return factory.makeObject(); } } public void destroyObject(final Object obj) throws Exception { synchronized (lock) { factory.destroyObject(obj); } } public boolean validateObject(final Object obj) { synchronized (lock) { return factory.validateObject(obj); } } public void activateObject(final Object obj) throws Exception { synchronized (lock) { factory.activateObject(obj); } } public void passivateObject(final Object obj) throws Exception { synchronized (lock) { factory.passivateObject(obj); } } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedPoolableObjectFactory"); sb.append("{factory=").append(factory); sb.append('}'); return sb.toString(); } } private static class SynchronizedKeyedPoolableObjectFactory implements KeyedPoolableObjectFactory { private final Object lock; private final KeyedPoolableObjectFactory keyedFactory; SynchronizedKeyedPoolableObjectFactory(final KeyedPoolableObjectFactory keyedFactory) throws IllegalArgumentException { if (keyedFactory == null) { throw new IllegalArgumentException("keyedFactory must not be null."); } this.keyedFactory = keyedFactory; lock = new Object(); } public Object makeObject(final Object key) throws Exception { synchronized (lock) { return keyedFactory.makeObject(key); } } public void destroyObject(final Object key, final Object obj) throws Exception { synchronized (lock) { keyedFactory.destroyObject(key, obj); } } public boolean validateObject(final Object key, final Object obj) { synchronized (lock) { return keyedFactory.validateObject(key, obj); } } public void activateObject(final Object key, final Object obj) throws Exception { synchronized (lock) { keyedFactory.activateObject(key, obj); } } public void passivateObject(final Object key, final Object obj) throws Exception { synchronized (lock) { keyedFactory.passivateObject(key, obj); } } public String toString() { final StringBuffer sb = new StringBuffer(); sb.append("SynchronizedKeyedPoolableObjectFactory"); sb.append("{keyedFactory=").append(keyedFactory); sb.append('}'); return sb.toString(); } } /** * Encapsulate the logic for when the next poolable object should be discarded. */ private static class ErodingFactor { private final float factor; private transient volatile long nextShrink; private transient volatile int idleHighWaterMark; public ErodingFactor(final float factor) { this.factor = factor; nextShrink = System.currentTimeMillis() + (long)(900000 * factor); // now + 15 min * factor idleHighWaterMark = 1; } public void update(final int numIdle) { update(System.currentTimeMillis(), numIdle); } public void update(final long now, final int numIdle) { final int idle = Math.max(0, numIdle); idleHighWaterMark = Math.max(idle, idleHighWaterMark); final float maxInterval = 15f; final float minutes = maxInterval + ((1f-maxInterval)/idleHighWaterMark) * idle; nextShrink = now + (long)(minutes * 60000f * factor); } public long getNextShrink() { return nextShrink; } public String toString() { return "ErodingFactor{" + "factor=" + factor + ", idleHighWaterMark=" + idleHighWaterMark + '}'; } } private static class ErodingObjectPool implements ObjectPool { private final ObjectPool pool; private final ErodingFactor factor; public ErodingObjectPool(final ObjectPool pool, final float factor) { this.pool = pool; this.factor = new ErodingFactor(factor); } public Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException { return pool.borrowObject(); } public void returnObject(final Object obj) { boolean discard = false; final long now = System.currentTimeMillis(); synchronized (pool) { if (factor.getNextShrink() < now) { // XXX: Pool 3: move test out of sync block final int numIdle = pool.getNumIdle(); if (numIdle > 0) { discard = true; } factor.update(now, numIdle); } } try { if (discard) { pool.invalidateObject(obj); } else { pool.returnObject(obj); } } catch (Exception e) { // swallowed } } public void invalidateObject(final Object obj) { try { pool.invalidateObject(obj); } catch (Exception e) { // swallowed } } public void addObject() throws Exception, IllegalStateException, UnsupportedOperationException { pool.addObject(); } public int getNumIdle() throws UnsupportedOperationException { return pool.getNumIdle(); } public int getNumActive() throws UnsupportedOperationException { return pool.getNumActive(); } public void clear() throws Exception, UnsupportedOperationException { pool.clear(); } public void close() { try { pool.close(); } catch (Exception e) { // swallowed } } public void setFactory(final PoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { pool.setFactory(factory); } public String toString() { return "ErodingObjectPool{" + "factor=" + factor + ", pool=" + pool + '}'; } } private static class ErodingKeyedObjectPool implements KeyedObjectPool { private final KeyedObjectPool keyedPool; private final ErodingFactor erodingFactor; public ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) { this(keyedPool, new ErodingFactor(factor)); } protected ErodingKeyedObjectPool(final KeyedObjectPool keyedPool, final ErodingFactor erodingFactor) { if (keyedPool == null) { throw new IllegalArgumentException("keyedPool must not be null."); } this.keyedPool = keyedPool; this.erodingFactor = erodingFactor; } public Object borrowObject(final Object key) throws Exception, NoSuchElementException, IllegalStateException { return keyedPool.borrowObject(key); } public void returnObject(final Object key, final Object obj) throws Exception { boolean discard = false; final long now = System.currentTimeMillis(); final ErodingFactor factor = getErodingFactor(key); synchronized (keyedPool) { if (factor.getNextShrink() < now) { final int numIdle = numIdle(key); if (numIdle > 0) { discard = true; } factor.update(now, numIdle); } } try { if (discard) { keyedPool.invalidateObject(key, obj); } else { keyedPool.returnObject(key, obj); } } catch (Exception e) { // swallowed } } protected int numIdle(final Object key) { return getKeyedPool().getNumIdle(); } protected ErodingFactor getErodingFactor(final Object key) { return erodingFactor; } public void invalidateObject(final Object key, final Object obj) { try { keyedPool.invalidateObject(key, obj); } catch (Exception e) { // swallowed } } public void addObject(final Object key) throws Exception, IllegalStateException, UnsupportedOperationException { keyedPool.addObject(key); } public int getNumIdle() throws UnsupportedOperationException { return keyedPool.getNumIdle(); } public int getNumIdle(final Object key) throws UnsupportedOperationException { return keyedPool.getNumIdle(key); } public int getNumActive() throws UnsupportedOperationException { return keyedPool.getNumActive(); } public int getNumActive(final Object key) throws UnsupportedOperationException { return keyedPool.getNumActive(key); } public void clear() throws Exception, UnsupportedOperationException { keyedPool.clear(); } public void clear(final Object key) throws Exception, UnsupportedOperationException { keyedPool.clear(key); } public void close() { try { keyedPool.close(); } catch (Exception e) { // swallowed } } public void setFactory(final KeyedPoolableObjectFactory factory) throws IllegalStateException, UnsupportedOperationException { keyedPool.setFactory(factory); } protected KeyedObjectPool getKeyedPool() { return keyedPool; } public String toString() { return "ErodingKeyedObjectPool{" + "erodingFactor=" + erodingFactor + ", keyedPool=" + keyedPool + '}'; } } private static class ErodingPerKeyKeyedObjectPool extends ErodingKeyedObjectPool { private final float factor; private final Map factors = Collections.synchronizedMap(new HashMap()); public ErodingPerKeyKeyedObjectPool(final KeyedObjectPool keyedPool, final float factor) { super(keyedPool, null); this.factor = factor; } protected int numIdle(final Object key) { return getKeyedPool().getNumIdle(key); } protected ErodingFactor getErodingFactor(final Object key) { ErodingFactor factor = (ErodingFactor)factors.get(key); // this may result in two ErodingFactors being created for a key // since they are small and cheap this is okay. if (factor == null) { factor = new ErodingFactor(this.factor); factors.put(key, factor); } return factor; } public String toString() { return "ErodingPerKeyKeyedObjectPool{" + "factor=" + factor + ", keyedPool=" + getKeyedPool() + '}'; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy