FileDocCategorySizeDatePackage
AbstractPool.javaAPI DocGlassfish v2 API15018Fri May 04 22:32:16 BST 2007com.sun.enterprise.util.pool

AbstractPool

public abstract class AbstractPool extends Object implements Pool

Abstract pool provides the basic implementation of an object pool. The implementation uses a linked list to maintain a collection of (available) objects. If the pool is empty it simply creates one using the ObjectFactory instance. Subclasses can change this behaviour by overriding getObject(...) and returnObject(....) methods. This class provides basic support for synchronization, event notification, pool shutdown and pool object recycling. It also does some very basic bookkeeping like the number of objects created, number of threads waiting for object.

Subclasses can make use of these book-keeping data to provide complex pooling mechanism like LRU / MRU / Random. Also, note that AbstractPool does not have a notion of pool limit. It is upto to the derived classes to implement these features.

Fields Summary
static Logger
_logger
protected boolean
bDebug
protected Collection
collection
protected ArrayList
listeners
protected ObjectFactory
factory
protected int
waitCount
protected int
createdCount
protected Object
onHold
protected Object
closed
protected static final com.sun.enterprise.util.ApproximateClock
_clock
protected com.sun.enterprise.util.scheduler.PeriodicEventScheduler
scheduler
Constructors Summary
protected AbstractPool()

    
    
      
    	scheduler = PeriodicEventScheduler.getInstance();
    
Methods Summary
public booleanaddPoolListener(PoolListener listener)
Add a PoolListener

param
listener The pool listener

    	synchronized (this) {
    		if (listeners == null) {
    			listeners = new ArrayList();
    			listeners.add(listener);
    			return true;
    		}
    		
    		if (listeners.indexOf(listener) == -1) {
    			listeners.add(listener);
    			return true;
    		} else {
    			return false;
    		}
    	}
    
public voidafterCreate(java.lang.Object object)
Called after an object is created using factory.create(....)

param
The created object.

    	if (listeners != null) {
    		int size = listeners.size();
    		for (int i=0; i<size; i++) {
    			((PoolListener) listeners.get(i)).afterCreate(object);
    		}
    	}
    
public voidafterNotify(java.lang.Object object)
Called by the thread that has been notified.

    	if (listeners != null) {
    		int size = listeners.size();
    		for (int i=0; i<size; i++) {
    			((PoolListener) listeners.get(i)).afterNotify(object);
    		}
    	}
    
public voidbeforeDestroy(java.lang.Object object)
Called before an object is destroyed using factory.destroy(object)

param
The object to be destroyed.

    	if (listeners != null) {
    		int size = listeners.size();
    		for (int i=0; i<size; i++) {
    			((PoolListener) listeners.get(i)).beforeDestroy(object);
    		}
    	}
    
public voidbeforeWait(java.lang.Object object)
Called by the thread that is about to wait.

    	if (listeners != null) {
    		int size = listeners.size();
    		for (int i=0; i<size; i++) {
    			((PoolListener) listeners.get(i)).beforeWait(object);
    		}
    	}
    
protected abstract booleancanCreate()

protected abstract java.lang.Objectcheckin(java.lang.Object object)
Notification when an object is put back into the pool (checkin).

param
The object to be returned back to the pool.
return
Any non null value can be returned to signal that the object was indeed added to the pool. This class always adds the object to the pool (at the end of the collection), it returns non-null value. Subclasses can override this behaviour.

protected abstract java.lang.Objectcheckout(java.lang.Object param)
Notification when an object is given out from the pool (checout).

return
The object that has to be returned to the application. A null value must be returned if no object can be returned to the application. Since this class always returns the last node from the collection, it returns non-null value. Subclasses can override this behaviour.

public voidclose()
Closes the current pool. No further getObject(....)s are allowed, while returnObject() and destroyObjects() are allowed.

    	//first clean up all objects
   		onClose();
    	synchronized (collection) {
    		closed = "__Closed__";
    		int diff = collection.size() - this.waitCount;
    		destroyPoolObjects(diff);
    		//We do not need to change the factory as all fresh getObject()
    		//	requests are blocked well before the synchronized access to the
    		//	collection (or pool).
    		//this.factory = new ClosedObjectFactory(this.factory);
    	}
    
public voiddestroyObject(java.lang.Object object)
Destroys an Object. Note that applications should not ignore the reference to the object that they got from getObject(). An object that is obtained through getObject() must always be returned back to the pool using either returnObject(obj) or through destroyObject(obj). This method tells that the object should be destroyed and cannot be reused.

		beforeDestroy(object);
    	factory.destroy(object);
    	synchronized (collection) {
    		createdCount--;
    		if (waitCount > 0) {
    			collection.notify();
    		}
    	}
    
public intdestroyPoolObjects()
Destroy the available objects in the pool.

    	return destroyPoolObjects(collection.size());
    
public intdestroyPoolObjects(int count)
Destroy 'count' available objects in the pool.

    	if (count <= 0) {
    		return 0;
    	}
    	
    	Object[] array = collection.toArray();
    	ArrayList arrayList = null;
    	synchronized (collection) {
    		if (count > collection.size()) {
    			count = collection.size();
    		}
    		arrayList = new ArrayList(count);
    		for (int i=0; i<count; i++) {
   				arrayList.add(checkout(null));
    		}
    		count = arrayList.size();
    		createdCount -= count;
    	}
    	
    	for (int i=0; i<count; i++) {
   			factory.destroy(arrayList.get(i));
    	}
    	return count;
    
public java.lang.ObjectgetObject(boolean canWait, java.lang.Object param)
Get an object. Application can use pool.getObject() to get an object instead of using new XXX().

param
canWait Must be true if the calling thread is willing to wait for infinite time to get an object, false if the calling thread does not want to wait at all.
exception
Throws InterruptedException if the thread was interrupted while waiting

		Object object;

		if (closed != null) {
			throw new PoolException("Pool closed. Cannot obtain object");	
		}
		
		synchronized (collection) {
			while (true) {
				if (collection.size() > 0) {
					if ( (object = checkout(param)) != null) {
						return object;
					}
				} else if (canCreate()) {
					createdCount++;
					break;
				}
					
				if (canWait) {
					try {
						waitCount++;
						beforeWait(param);
						collection.wait();
						afterNotify(param);
						waitCount--;
					} catch (InterruptedException inEx) {
						throw new RequestInterruptedException("InterruptedException", inEx);
					}
				} else {
					return null;
				}
			}
		}
			
		try {
			object = factory.create(param);
		} catch (PoolException poolEx) {
			synchronized (collection) {
				createdCount--;
			}
			throw poolEx;
		}
		afterCreate(object);
					
		return object;
	
public java.lang.ObjectgetObject(long waitFor, java.lang.Object param)
Get an object. Application can use pool.getObject() to get an object instead of using new XXX(). The method throws TimedoutException if an object could not be returned in 'waitForMillis' millisecond.

param
waitFor the amount of time the thread is willing to wait.
exception
Throws InterruptedException if the thread was interrupted while waiting
exception
Throws TimedoutException if an object could not be obtained from the pool within the specified time.


		if (closed != null) {
			throw new PoolException("Pool closed. Cannot obtain object");	
		}
		
	    long now = _clock.getTime();
    	long timeLeft = waitFor;
		long startTime = now;
		Object object;
		synchronized (collection) {
			while (true) {
				if (collection.size() > 0) {
					if ( (object = checkout(param)) != null) {
						return object;
					}
				} else if (canCreate()) {
					createdCount++;
					break;
				}
				
				if (timeLeft > 0) {
					try {
						waitCount++;
						beforeWait(param);
						collection.wait();
						afterNotify(param);
						waitCount--;
					} catch (InterruptedException inEx) {
						throw new RequestInterruptedException("InterruptedException", inEx);
					}
				} else {
					return null;
				}
				now = _clock.getTime();
        		timeLeft =  now - startTime;
        		startTime = now;
			}
		}
		
		try {
			object = factory.create(param);
		} catch (PoolException poolEx) {
			synchronized (collection) {
				createdCount--;
			}
			throw poolEx;
		}
		afterCreate(object);

		return object;
    
public booleanisClosed()
Test if the pool is closed or not

return
True if the pool is closed, false if not.

    	return (closed != null);
    
public voidonClose()
Called when the pool is closed.

    	if (listeners != null) {
    		int size = listeners.size();
    		for (int i=0; i<size; i++) {
    			((PoolListener) listeners.get(i)).onClose();
    		}
    	}
    
public voidpreload(int count)
Preload the pool with objects.

param
count the number of objects to be added.

    	if (count <= 0) {
    		return;
    	}
    	
    	ArrayList tempList = new ArrayList(count);
    	for (int i=0; i<count; i++) {
    		try {
    			tempList.add(factory.create(null));
    		} catch (PoolException poolEx) {
    			
    		}
    	}

		count = tempList.size();
    	synchronized (collection) {
    		for (int i=0; i<count; i++) {
    			checkin(tempList.get(i));
    		}
    		createdCount += count;
    	}
//Bug 4677074    	if(bDebug) System.out.println("After preload(" + count + "): Size: " + collection.size());
//Bug 4677074 begin
	if(com.sun.enterprise.util.logging.Debug.enabled) _logger.log(Level.FINE,"After preload(" + count + "): Size: " + collection.size());
//Bug 4677074 end
    
public booleanremovePoolListener(PoolListener listener)
Add a PoolListener

param
listener The pool listener

    	synchronized (this) {
    		if (listeners == null) {
    			return false;
    		} else {
    			return listeners.remove(listener);
    		}
    	}
    
public voidreturnObject(java.lang.Object object)
Return an object back to the pool. An object that is obtained through getObject() must always be returned back to the pool using either returnObject(obj) or through destroyObject(obj).

    	synchronized (collection) {
    		if (closed != null) {
    			if (waitCount == 0) {
    				destroyObject(object);
    				return;
    			}
    		}
    		
    		checkin(object);
    		if (waitCount > 0) {
    			collection.notify();
	    	}
    	}
    
public intsize()

    	return collection.size();