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

org.codehaus.plexus.util.SweeperPool Maven / Gradle / Ivy

package org.codehaus.plexus.util;

/*
 * Copyright The Codehaus 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.
 */

import java.util.ArrayList;

/**
 * Pools a bunch of objects . Runs a sweeper periodically to keep it down to size. The objects in the pool first get
 * disposed first.
 *
 * @author Bert van Brakel
 *
 */
public class SweeperPool
{
    /***/
    private static final boolean DEBUG = false;

    /** Sweeps the pool periodically to trim it's size */
    private transient Sweeper sweeper;

    /** Absolute maximum size of the pool. */
    private transient int maxSize;

    /** The size the pool gets trimmed down to */
    private transient int minSize;

    /**
     * When the sweeper runs and the pool is over this size, then the pool is trimmed
     */
    private int triggerSize;

    /** Holds the pooled objects */
    private ArrayList pooledObjects;

    /** Flag indicating this pool is shuting down */
    private boolean shuttingDown = false;

    // private Vector used;

    /**
     * There are a number of settings to control how the pool operates.
     * @param maxSize if the pool has reached this size, any objects added are immediately disposed. If the
     *      pool is this size when the sweeper runs, then the pool is also trimmed to minSize irrespective of
     *      the triggerSize.
     * @param minSize - this is the size the pool is trimmed to
     * @param  triggerSize - this determines if the pool is trimmed when the sweeper runs. If the pool size is
     * greater or equal than this value then the pool is trimmed to minSize.
     *
     * @param sweepInterval how often the sweeper runs. Is actually the time since the sweeper last finished
     * a pass. 0 if the sweeper should not run.
     * @param intialCapacity the intial capacity
     * 

Any value less than 0 is automatically converted to 0

*/ public SweeperPool( int maxSize, int minSize, int intialCapacity, int sweepInterval, int triggerSize ) { super(); this.maxSize = saneConvert( maxSize ); this.minSize = saneConvert( minSize ); this.triggerSize = saneConvert( triggerSize ); pooledObjects = new ArrayList( intialCapacity ); // only run a sweeper if sweep interval is positive if ( sweepInterval > 0 ) { sweeper = new Sweeper( this, sweepInterval ); sweeper.start(); } } private int saneConvert( int value ) { return Math.max( value, 0 ); } /** * Return the pooled object * @return first available object from the pool */ public synchronized Object get() { if ( ( pooledObjects.size() == 0 ) || shuttingDown ) { return null; } else { Object obj = pooledObjects.remove( 0 ); objectRetrieved( obj ); // used.add(obj); return obj; } } /** * Add an object to the pool * * @param obj the object to pool. Can be null. * @return true if the object was added to the pool, false if it was disposed or null */ public synchronized boolean put( Object obj ) { objectAdded( obj ); if ( ( obj != null ) && ( pooledObjects.size() < maxSize ) && ( shuttingDown == false ) ) { pooledObjects.add( obj ); return true; } else if ( obj != null ) { // no longer need the object, so dispose it objectDisposed( obj ); } return false; } /** * Return the number of pooled objects. This is never greater than t maximum size of the pool * * @return the number of pooled objects */ public synchronized int getSize() { return pooledObjects.size(); } /** * Dispose of this pool. Stops the sweeper and disposes each object in the pool */ public void dispose() { shuttingDown = true; if ( sweeper != null ) { sweeper.stop(); try { sweeper.join(); } catch ( InterruptedException e ) { System.err.println( "Unexpected exception occurred: " ); e.printStackTrace(); } } synchronized ( this ) { // use an array here as objects may still be being put back in the pool // and we don't want to throw a ConcurrentModificationException Object[] objects = pooledObjects.toArray(); for ( Object object : objects ) { objectDisposed( object ); } pooledObjects.clear(); } } /** * A pool has been disposed if has been shutdown and the sweeper has completed running. * * @return true if the pool has been disposed, false otherwise */ boolean isDisposed() { if ( !shuttingDown ) { return false; } // A null sweeper means one was never started. if ( sweeper == null ) { return true; } return sweeper.hasStopped(); } /** * Trim the pool down to min size */ public synchronized void trim() { if ( ( ( triggerSize > 0 ) && ( pooledObjects.size() >= triggerSize ) ) || ( ( maxSize > 0 ) && ( pooledObjects.size() >= maxSize ) ) ) { while ( pooledObjects.size() > minSize ) { objectDisposed( pooledObjects.remove( 0 ) ); } } } /** * Override this to be notified of object disposal. Called after the object has been removed. Occurs when the pool * is trimmed. * * @param obj the Object */ public void objectDisposed( Object obj ) { } /** * Override this to be notified of object addition. Called before object is to be added. * * @param obj the Object */ public void objectAdded( Object obj ) { } /** * Override this to be notified of object retrieval. Called after object removed from the pool, but before returned * to the client. * * @param obj the Object */ public void objectRetrieved( Object obj ) { } /** * Periodically at sweepInterval goes through and tests if the pool should be trimmed. * * @author bert */ private static class Sweeper implements Runnable { private final transient SweeperPool pool; private transient boolean service = false; private final transient int sweepInterval; private transient Thread t = null; /** * */ public Sweeper( SweeperPool pool, int sweepInterval ) { super(); this.sweepInterval = sweepInterval; this.pool = pool; } /** * Run the sweeper. * * @see java.lang.Runnable#run() */ @Override public void run() { debug( "started" ); if ( sweepInterval > 0 ) { synchronized ( this ) { while ( service ) { try { // wait specified number of seconds // before running next sweep wait( sweepInterval * 1000 ); } catch ( InterruptedException e ) { } runSweep(); } } } debug( "stopped" ); } public void start() { if ( !service ) { service = true; t = new Thread( this ); t.setName( "Sweeper" ); t.start(); } } public synchronized void stop() { service = false; notifyAll(); } void join() throws InterruptedException { t.join(); } boolean hasStopped() { return !service && !t.isAlive(); } private final void debug( String msg ) { if ( DEBUG ) { System.err.println( this + ":" + msg ); } } private void runSweep() { debug( "runningSweep. time=" + System.currentTimeMillis() ); pool.trim(); } } }