// SimplePool.java

package ed.util;

import java.util.*;

/** @expose */
public abstract class SimplePool<T> {

    /** Initializes a new pool of objects.
     * @param name name for the pool
     * @param maxToKeep max to hold to at any given time can be -1
     * @param maxTotal how many to have at any given time
     */
    public SimplePool( String name , int maxToKeep , int maxTotal ){
        this( name , maxToKeep , maxTotal , false );
    }

    /** Initializes a new pool of objects.
     * @param name name for the pool
     * @param maxToKeep max to hold to at any given time can be -1
     * @param maxTotal how many to have at any given time
     * @param trackLeaks if leaks should be tracked
     */
    public SimplePool( String name , int maxToKeep , int maxTotal , boolean trackLeaks ){
        _name = name;
        _maxToKeep = maxToKeep;
        _maxTotal = maxTotal;
        _trackLeaks = trackLeaks;
    }

    /** Creates a new object of this pool's type.
     * @return the new object.
     */
    protected abstract T createNew();

    /** Checks if a given object is okay.
     * @return true
     */
    public boolean ok( T t ){
        return true;
    }

    /** If there is space available, add the given object to the pool.
     * @param t Object to add
     */
    public void done( T t ){
        _where.remove( _hash( t ) );

        if ( ! ok( t ) )
            return;

        synchronized ( _avail ){
            if ( _maxToKeep > 0 && _avail.size() < _maxToKeep )
                _avail.add( t );
        }
    }

    /** Gets an object from the pool.
     * @return An object from the pool
     */
    public T get(){
        final T t = _get();
        if ( t != null && _trackLeaks ){
            Throwable stack = new Throwable();
            stack.fillInStackTrace();
            _where.put( _hash( t ) , stack );
        }
        return t;
    }

    private int _hash( T t ){
        return System.identityHashCode( t );
    }

    private T _get(){
        while ( true ){
            synchronized ( _avail ){
                if ( _avail.size() > 0 )
                    return _avail.remove( _avail.size() - 1 );

                if ( _maxTotal <= 0 || _all.size() < _maxTotal ){
                    T t = createNew();
                    _all.add( t );
                    return t;
                }

                if ( _trackLeaks && _trackPrintCount++ % 200 == 0 ){
                    _wherePrint();
                    _trackPrintCount = 1;
                }
            }
            ThreadUtil.sleep( 15 );
        }
    }

    private void _wherePrint(){
        StringBuilder buf = new StringBuilder( "Pool : " + _name + " waiting b/c of\n" );
        for ( Throwable t : _where.values() ){
            buf.append( "--\n" );
            final StackTraceElement[] st = t.getStackTrace();
            for ( int i=0; i<st.length; i++ )
                buf.append( "  " ).append( st[i] ).append( "\n" );
            buf.append( "----\n" );
        }

        System.out.println( buf );
    }

    /** Clears the pool of all objects. */
    protected void clear(){
        _avail.clear();
        _all.clear();
        _where.clear(); // is this correct
    }

    /** @unexpose */
    final String _name;
    /** @unexpose */
    final int _maxToKeep;
    /** @unexpose */
    final int _maxTotal;
    /** @unexpose */
    final boolean _trackLeaks;

    private final List<T> _avail = new ArrayList<T>();
    private final WeakBag<T> _all = new WeakBag<T>();
    private final Map<Integer,Throwable> _where = new HashMap<Integer,Throwable>();

    private int _trackPrintCount = 0;
}

@@ -118,204 +118,41 @@
 /** 
-Initializes a new pool of objects.%0A     * @param name name for the pool%0A     * @param maxToKeep max to hold to at any given time can be -1%0A     * @param maxTotal how many to have at any given time
+%0A     * See full constructor docs
 %0A   
@@ -425,18 +425,30 @@
 time
- can be -1
+. if %3C 0 then no limit
 %0A   
@@ -471,16 +471,11 @@
 tal 
-how many
+max
  to 
@@ -480,32 +480,78 @@
 o have a
-t any given time
+llocated at any point.  if there are no more, get() will block
 %0A     * 
@@ -958,61 +958,295 @@
 /** 
-Checks if a given object is okay.%0A     * @return true
+%0A     * callback to determin if an object is ok to be added back to the pool%0A     * by default just returns true.  override to return false in some cases if you want %0A     * an object to be tossed under certain conditions%0A     * @return true iff the object is ok to be added back to pool
 %0A   
@@ -1320,49 +1320,50 @@
 /** 
-If there is space available, add the give
+%0A     * call done when you are done with a
 n ob
@@ -1367,18 +1367,20 @@
  object 
-to
+form
  the poo
@@ -1372,33 +1372,92 @@
 ct form the pool
-.
+%0A     * if there is room and the object is ok will get added
 %0A     * @param t
@@ -1777,16 +1777,56 @@
 e pool.%0A
+     * will block if none are available%0A
      * @

fix docs