FileDocCategorySizeDatePackage
NonBlockingPool.javaAPI DocGlassfish v2 API22519Fri May 04 22:33:00 BST 2007com.sun.ejb.containers.util.pool

NonBlockingPool

public class NonBlockingPool extends AbstractPool

NonBlockingPool pool provides the basic implementation of an object pool. The implementation uses a linked list to maintain a list 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
private String
poolName
private TimerTask
poolTimerTask
protected boolean
addedResizeTask
protected boolean
addedIdleBeanWork
protected boolean
inResizing
private boolean
maintainSteadySize
private int
resizeTaskCount
private int
timerTaskCount
Constructors Summary
protected NonBlockingPool()


      
    
public NonBlockingPool(String poolName, ObjectFactory factory, int steadyPoolSize, int resizeQuantity, int maxPoolSize, int idleTimeoutInSeconds, ClassLoader loader)

        this.poolName = poolName;
    	initializePool(factory, steadyPoolSize, resizeQuantity, maxPoolSize,
                       idleTimeoutInSeconds, loader);
    
Methods Summary
private voidaddResizeTaskForImmediateExecution()

        try {
            ReSizeWork work = new ReSizeWork();
            ContainerWorkPool.addLast(work);
            if(_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE,
                     "[Pool-" + poolName + "]: Added PoolResizeTimerTask...");
            }
            resizeTaskCount++;
        } catch (Exception ex) {
            synchronized (list) {
                addedResizeTask = false;
            }
            if(_logger.isLoggable(Level.WARNING)) {
            	_logger.log(Level.WARNING, 
                            "[Pool-"+poolName+"]: Cannot perform "
                            + " pool resize task", ex);
            }
        }
    
public voidclose()
Close the pool

        synchronized (list) {
            if (poolTimerTask != null) {
                try {
                    poolTimerTask.cancel();	
                    if(_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE,
                            "[Pool-"+poolName+"]: Cancelled pool timer task "
                                    + " at: " + (new java.util.Date()));
                    }
                } catch (Throwable th) {
                    //Can safely ignore this!!
                }
            }
	
            if(_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE,"[Pool-"+poolName+"]: Destroying "
                            + list.size() + " beans from the pool...");
            }
	
            // since we're calling into ejb code, we need to set context
            // class loader
            ClassLoader origLoader = 
                Utility.setContextClassLoader(containerClassLoader);

            Object[] array = list.toArray();
            for (int i=0; i<array.length; i++) {
                try {
                    destroyedCount++;
                    try {
                        factory.destroy(array[i]);
                    } catch (Throwable th) {
                        _logger.log(Level.FINE, "exception in close", th);
                    }
                } catch (Throwable th) {
                    _logger.log(Level.WARNING,
                        "[Pool-"+poolName+"]: Error while destroying", th);
                }
            }
            if(_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE,"Pool-"+poolName+"]: Pool closed....");
            }
            list.clear(); 

            Utility.setContextClassLoader(origLoader);
        }

        // helps garbage collection
        this.list                  = null;
        this.factory               = null;
        this.poolTimerTask         = null;
        this.containerClassLoader  = null;
        
    
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.

    	synchronized (list) {
            destroyedCount++;
    	}
        
        try {
            factory.destroy(object);
        } catch (Exception ex) {
            _logger.log(Level.FINE, "exception in destroyObject", ex);
        }
    
protected voiddoResize()

        
        //We need to set the context class loader for this (deamon) thread!!
        final Thread currentThread = Thread.currentThread();
        final ClassLoader previousClassLoader = 
            currentThread.getContextClassLoader();
        final ClassLoader ctxClassLoader = containerClassLoader;
	
        long startTime = 0;
        boolean enteredResizeBlock = false;
        try {
            if(System.getSecurityManager() == null) {
                currentThread.setContextClassLoader(ctxClassLoader);
            } else {
                java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedAction() {
                    public java.lang.Object run() {
                        currentThread.setContextClassLoader(ctxClassLoader);
                        return null;
                    }
                });
            }

            if(_logger.isLoggable(Level.FINE)) {
                _logger.log(Level.FINE, 
                    "[Pool-"+poolName+"]: Resize started at: "
                  + (new java.util.Date())+" steadyPoolSize ::"+steadyPoolSize
                  + " resizeQuantity ::"+resizeQuantity+" maxPoolSize ::" +
                  maxPoolSize );
            }
            startTime = System.currentTimeMillis();

            ArrayList removeList = new ArrayList();
            int populateCount = 0;
            synchronized (list) {
                if (inResizing == true) {
                    return;
                }

                enteredResizeBlock = true;
                inResizing = true;
                
                int curSize = list.size();

                if (curSize > steadyPoolSize) {

                    //possible to reduce pool size....
                    if ((idleTimeoutInSeconds <= 0)  || 
                        (resizeQuantity <= 0)) {
                        return;
                    }
                    int victimCount = 
                        (curSize > (steadyPoolSize + resizeQuantity) )
                        ? resizeQuantity : (curSize - steadyPoolSize);
                    long allowedIdleTime = System.currentTimeMillis() -
                        idleTimeoutInSeconds*1000;
                    if(_logger.isLoggable(Level.FINE)) {
                        _logger.log(Level.FINE, 
                                    "[Pool-"+poolName+"]: Resize:: reducing "
                                    + " pool size by: " + victimCount);
                    }
                    for (int i=0; i<victimCount; i++) {
                        //removeList.add(list.remove(--curSize));
               		//destroyedCount++;
                        EJBContextImpl ctx = (EJBContextImpl) list.get(0);
                        if (ctx.getLastTimeUsed() <= allowedIdleTime) {
                            removeList.add(list.remove(0));
                            destroyedCount++;
                        } else {
                            break;
                        }
                    }
                } else if (curSize < steadyPoolSize) {

                    //Need to populate....
                    if (maintainSteadySize  == false) {
                        return;
                    }

                    if (resizeQuantity <= 0) {
                        populateCount = steadyPoolSize - curSize; 
                    } else {
                        while ((curSize + populateCount) < steadyPoolSize) {
                            populateCount += resizeQuantity;
                        }
                        if ((curSize + populateCount) > maxPoolSize) {
                            populateCount -= (curSize + populateCount) - maxPoolSize;
                        }
                    }
                }
            }
            
            if (removeList.size() > 0) {
                int sz = removeList.size();
                for (int i=0; i<sz; i++) {
                    try {
                        factory.destroy(removeList.get(i));
                    } catch (Throwable th) {
                        _logger.log(Level.FINE, "exception in doResize", th);
                    }
                }
            }

            if (populateCount > 0) {
                //preload adds items inside a sync block....

                if(_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, 
                            "[Pool-"+poolName+"]: Attempting to preload "
                            + populateCount + " beans. CurSize/MaxPoolSize: "
                            + list.size() + "/" + maxPoolSize);
                }

                preload(populateCount);

                if(_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE, 
                            "[Pool-"+poolName+"]: After preload "
                            + "CurSize/MaxPoolSize: "
                            + list.size() + "/" + maxPoolSize);
                }
            }
            
            
        } catch (Throwable th) {
            _logger.log(Level.WARNING,
                        "[Pool-"+poolName+"]: Exception during reSize", th);

        } finally {
            
            if (enteredResizeBlock) {
                synchronized (list) {
                    inResizing = false;
                }
            }
            if(System.getSecurityManager() == null) {
                currentThread.setContextClassLoader(previousClassLoader);
            } else {
                java.security.AccessController.doPrivileged(
                        new java.security.PrivilegedAction() {
                    public java.lang.Object run() {
                        currentThread.setContextClassLoader(previousClassLoader);
                        return null;
                    }
                });
            }
        }

        long endTime = System.currentTimeMillis();
        if(_logger.isLoggable(Level.FINE)) {
            _logger.log(Level.FINE, 
                "[Pool-"+poolName+"]: Resize completed at: "
                + (new java.util.Date()) + "; after reSize: " + 
                getAllAttrValues());
            _logger.log(Level.FINE, "[Pool-"+poolName+"]: Resize took: "
                        + ((endTime-startTime)/1000.0) + " seconds.");
        }
    
public java.lang.StringgetAllAttrValues()

        StringBuffer sbuf = new StringBuffer("[Pool-"+poolName+"] ");
        sbuf.append("CC=").append(createdCount).append("; ")
            .append("DC=").append(destroyedCount).append("; ")
            .append("CS=").append(list.size()).append("; ")
            .append("SS=").append(steadyPoolSize).append("; ")
            .append("MS=").append(maxPoolSize).append(";");
        return sbuf.toString();
    
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.

        return getObject(param);
    
public java.lang.ObjectgetObject(long maxWaitTime, java.lang.Object param)

        return getObject(param);
    
public java.lang.ObjectgetObject(java.lang.Object param)

        boolean toAddResizeTask = false;
        Object obj = null;
        synchronized (list) {
            int size = list.size();
            if (size > steadyPoolSize) {
                poolSuccess++;
                return list.remove(size-1);
            } else if (size > 0) {
                poolSuccess++;
                if ((maintainSteadySize) && (addedResizeTask == false)) {
                    toAddResizeTask = addedResizeTask = true;
                    obj = list.remove(size-1);
                } else {
                    return list.remove(size-1);
                }
            } else {
                if ((maintainSteadySize) && (addedResizeTask == false)) {
                    toAddResizeTask = addedResizeTask = true;
                }
                createdCount++;	//hope that everything will be OK.
            }
        }
        
        if (toAddResizeTask) {
            addResizeTaskForImmediateExecution();
        }
        
        if (obj != null) {
            return obj;
        }
        
        try {
            return factory.create(param);
        } catch (RuntimeException th) {
            synchronized (list) {
                createdCount--;
            }
            throw th;
        }
    
protected voidinitializePool(ObjectFactory factory, int steadyPoolSize, int resizeQuantity, int maxPoolSize, int idleTimeoutInSeconds, java.lang.ClassLoader loader)

        list = new ArrayList();
        
        this.factory = factory;
        this.steadyPoolSize = (steadyPoolSize <= 0) ? 0 : steadyPoolSize;
        this.resizeQuantity = (resizeQuantity <= 0) ? 0 : resizeQuantity;
        this.maxPoolSize = (maxPoolSize <= 0)
            ? Integer.MAX_VALUE : maxPoolSize;
        this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
            ? this.maxPoolSize : this.steadyPoolSize;
        this.idleTimeoutInSeconds = 
            (idleTimeoutInSeconds <= 0) ? 0 : idleTimeoutInSeconds;
        
        this.containerClassLoader = loader;
        
        this.maintainSteadySize = (this.steadyPoolSize > 0);
        if ((this.idleTimeoutInSeconds > 0) && (this.resizeQuantity > 0)) {
            try {
                this.poolTimerTask =  new PoolResizeTimerTask();
                ContainerFactoryImpl.getTimer().scheduleAtFixedRate
                    (poolTimerTask, idleTimeoutInSeconds*1000, 
                     idleTimeoutInSeconds*1000);
                if(_logger.isLoggable(Level.FINE)) {
                    _logger.log(Level.FINE,
                      "[Pool-" + poolName + "]: Added PoolResizeTimerTask...");
                }
            } catch (Throwable th) {
                _logger.log(Level.WARNING,"[Pool-" + 
                            poolName + "]: Could not add"
                            + " PoolTimerTask. Continuing anyway...", th);
            }
        }
    
protected voidpreload(int count)
Preload the pool with objects.

param
count the number of objects to be added.

    	
        ArrayList instances = new ArrayList(count);
        try {
            for (int i=0; i<count; i++) {
                instances.add(factory.create(null));
            }
    	} catch (Exception ex) {
            //Need not throw this exception up since we are pre-populating
    	}

        int sz = instances.size();
        if (sz == 0) {
            return;
        }
    	synchronized (list) {
            for (int i=0; i<sz; i++) {
                list.add(instances.get(i));
            }
            createdCount += sz;
    	}
    
public voidprepopulate(int count)
Prepopulate the pool with objects.

param
count the number of objects to be added.

        this.steadyPoolSize = (count <= 0) ? 0 : count;
        this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
            ? this.maxPoolSize : this.steadyPoolSize;
	
        if (this.steadyPoolSize > 0) {
            preload(this.steadyPoolSize);
        }
            
    
protected voidremove(int count)

        ArrayList removeList = new ArrayList();
        synchronized (list) {
            int size = list.size();
            for (int i=0; (i<count) && (size > 0); i++) {
                removeList.add(list.remove(--size));
                destroyedCount++;
            }
        }
        
        int sz = removeList.size();
        for (int i=0; i<sz; i++) {
            try {
                factory.destroy(removeList.get(i));
            } catch (Throwable th) {
                _logger.log(Level.FINE, "exception in remove", th);
            }
        }
    
protected voidremoveIdleObjects()

    
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 (list) {
            if (list.size() < maxPoolSize) {
                list.add(object);
                return;
            } else {
                destroyedCount++;
            }
        }
        
        try {
            factory.destroy(object);
        } catch (Exception ex) {
            _logger.log(Level.FINE, "exception in returnObj", ex);             
        }
    
public voidsetContainerClassLoader(java.lang.ClassLoader loader)

        this.containerClassLoader = loader;