Package com.sun.ejb.containers.util.pool

Source Code of com.sun.ejb.containers.util.pool.NonBlockingPool$ReSizeWork

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/**
* <BR> <I>$Source: /cvs/glassfish/appserv-core/src/java/com/sun/ejb/containers/util/pool/NonBlockingPool.java,v $</I>
* @author     $Author: tcfujii $
* @version    $Revision: 1.5 $ $Date: 2007/05/05 05:33:00 $
*/

package com.sun.ejb.containers.util.pool;

import java.util.*;

import com.sun.ejb.containers.ContainerFactoryImpl;
import java.util.logging.*;
import java.util.TimerTask;
import com.sun.logging.*;

import com.sun.enterprise.util.Utility;
import com.sun.ejb.containers.EJBContextImpl;

import com.sun.enterprise.util.threadpool.Servicable;
import com.sun.ejb.containers.util.ContainerWorkPool;

/**
* <p>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.
* <p> 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.
*/


public class NonBlockingPool
    extends AbstractPool
{

    private String    poolName;
    private TimerTask    poolTimerTask;
    protected boolean    addedResizeTask = false;
    protected boolean    addedIdleBeanWork = false;
    protected boolean    inResizing = false;
    private boolean    maintainSteadySize = false;
   
    private int      resizeTaskCount;
    private int      timerTaskCount;

    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);
    }

    protected void initializePool(ObjectFactory factory, int steadyPoolSize,
        int resizeQuantity, int maxPoolSize, int idleTimeoutInSeconds,
        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);
            }
        }
    }
   

    public void setContainerClassLoader(ClassLoader loader) {
        this.containerClassLoader = loader;
    }
   
    /**
     * 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.
     * 
     */
    public Object getObject(boolean canWait, Object param)
        throws PoolException
    {
        return getObject(param);
    }

    public Object getObject(long maxWaitTime, Object param)
        throws PoolException
    {
        return getObject(param);
    }

    public Object getObject(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;
        }
    }
   
    private void addResizeTaskForImmediateExecution() {
        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);
            }
        }
    }

    /**
     * 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).
     */
    public void returnObject(Object object) {
      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);            
        }
    }

    /**
     * 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.
     */
    public void destroyObject(Object object) {
      synchronized (list) {
            destroyedCount++;
      }
       
        try {
            factory.destroy(object);
        } catch (Exception ex) {
            _logger.log(Level.FINE, "exception in destroyObject", ex);
        }
    }
   
    /**
    * Preload the pool with objects.
    * @param count the number of objects to be added.
    */
    protected void preload(int count) {
     
        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;
      }
    }

    /**
    * Prepopulate the pool with objects.
    * @param count the number of objects to be added.
    */
    public void prepopulate(int count) {
        this.steadyPoolSize = (count <= 0) ? 0 : count;
        this.steadyPoolSize = (this.steadyPoolSize > this.maxPoolSize)
            ? this.maxPoolSize : this.steadyPoolSize;
 
        if (this.steadyPoolSize > 0) {
            preload(this.steadyPoolSize);
        }
           
    }
    /**
    * Close the pool
    */
    public void close() {
        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;
       
    }

    protected void remove(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 void removeIdleObjects() {
    }
   
    protected void doResize() {
       
        //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 String getAllAttrValues() {
        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();
    }

    private class ReSizeWork
        implements Servicable
    {
        public void prolog() {
        }
       
      public void service() {
            run();
        }
       
      public void epilog() {
        }

        public void run() {
            try {
                doResize();
            } catch (Exception ex) {
                _logger.log(Level.WARNING,
                    "[Pool-"+poolName+"]: Exception during reSize", ex);
            } finally {
                synchronized (list) {
                    addedResizeTask = false;
                }
            }
        }
    }

    private class IdleBeanWork
        implements Servicable
    {
        public void prolog() {
        }
       
      public void service() {
            run();
        }
       
      public void epilog() {
        }
       
        public void run() {
            try {
                doResize();
            } catch (Exception ex) {
            } finally {
                addedIdleBeanWork = false;
            }
        }
    }

    private class PoolResizeTimerTask
        extends java.util.TimerTask
    {
        Object    lock;
       
        PoolResizeTimerTask() {}
       
        PoolResizeTimerTask(Object lock) {
            this.lock = lock;
        }
       
        public void run() {
           
            try {
                if (addedIdleBeanWork == true) {
                    return;
                }
                IdleBeanWork work = new IdleBeanWork();
                ContainerWorkPool.addLast(work);
                addedIdleBeanWork = true;
            } catch (Exception ex) {
                _logger.log(Level.WARNING,
                            "[Pool-"+poolName+"]: Cannot perform "
                            + " pool idle bean cleanup", ex);
            }
 
        }
    } // End of class PoolResizeTimerTask

}
TOP

Related Classes of com.sun.ejb.containers.util.pool.NonBlockingPool$ReSizeWork

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.