net.lightbody.bmp.proxy.jetty.util.Pool.java Source code

Java tutorial

Introduction

Here is the source code for net.lightbody.bmp.proxy.jetty.util.Pool.java

Source

// ========================================================================
// $Id: Pool.java,v 1.13 2005/08/13 00:01:28 gregwilkins Exp $
// Copyright 1999-2004 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.
// ========================================================================

package net.lightbody.bmp.proxy.jetty.util;

import net.lightbody.bmp.proxy.jetty.log.LogFactory;
import org.apache.commons.logging.Log;

import java.io.Serializable;
import java.util.HashMap;

/* ------------------------------------------------------------ */
/** A pool of Objects.
 * <p>
 * @version $Id: Pool.java,v 1.13 2005/08/13 00:01:28 gregwilkins Exp $
 * @author Juancarlo Aez <juancarlo@modelistica.com>
 * @author Greg Wilkins <gregw@mortbay.com>
 */
public class Pool implements LifeCycle, Serializable {
    private static Log log = LogFactory.getLog(Pool.class);

    /* ------------------------------------------------------------ */
    static int __max = Integer.getInteger("POOL_MAX", 256).intValue();
    static int __min = Integer.getInteger("POOL_MIN", 2).intValue();

    /* ------------------------------------------------------------ */
    public static interface PondLife {
        int getID();

        void enterPool(Pool pool, int id);

        void poolClosing();

        void leavePool();
    }

    /* ------------------------------------------------------------------- */
    static HashMap __nameMap = new HashMap();

    /* ------------------------------------------------------------------- */
    private int _max = __max;
    private int _min = __min;
    private String _name;
    private String _className;
    private int _maxIdleTimeMs = 10000;
    private HashMap _attributes = new HashMap();

    private transient Class _class;
    private transient PondLife[] _pondLife; // Array of pondlife indexed by ID.
    private transient int[] _index; // Mapping of pondlife IDs.  Entries with indexes <_available are idle IDs.  Entries with indexes>_size are unused IDs.
    private transient int _size;
    private transient int _available;
    private transient int _running = 0;
    private transient long _lastShrink = 0; // control shrinking to once per maxIdleTime

    /* ------------------------------------------------------------------- */
    public static Pool getPool(String name) {
        return (Pool) __nameMap.get(name);
    }

    /* ------------------------------------------------------------------- */
    /* Construct
     */
    public Pool() {
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The name of the Pool.
     */
    public String getPoolName() {
        return _name;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @param name The pool name
     * @exception IllegalStateException If the name is already defined.
     */
    public void setPoolName(String name) throws IllegalStateException {
        synchronized (this) {
            synchronized (Pool.class) {
                if (_name != null && !_name.equals(name))
                    __nameMap.remove(_name);
                if (__nameMap.containsKey(name))
                    throw new IllegalStateException("Name already exists");
                _name = name;

                __nameMap.put(_name, this);
            }
        }
    }

    /* ------------------------------------------------------------ */
    /** Set the class.
     * @param poolClass The class
     * @exception IllegalStateException If the pool has already
     *            been started.
     */
    public void setPoolClass(Class poolClass) throws IllegalStateException {
        synchronized (this) {
            if (_class != poolClass) {
                if (_running > 0)
                    throw new IllegalStateException("Thread Pool Running");
                if (!PondLife.class.isAssignableFrom(poolClass))
                    throw new IllegalArgumentException("Not PondLife: " + poolClass);
                _class = poolClass;
                _className = _class.getName();
            }
        }
    }

    /* ------------------------------------------------------------ */
    public Class getPoolClass() {
        return _class;
    }

    /* ------------------------------------------------------------ */
    public int getMinSize() {
        return _min;
    }

    /* ------------------------------------------------------------ */
    public void setMinSize(int min) {
        _min = min;
    }

    /* ------------------------------------------------------------ */
    public int getMaxSize() {
        return _max;
    }

    /* ------------------------------------------------------------ */
    public void setMaxSize(int max) {
        _max = max;
    }

    /* ------------------------------------------------------------ */
    public int getMaxIdleTimeMs() {
        return _maxIdleTimeMs;
    }

    /* ------------------------------------------------------------ */
    public void setMaxIdleTimeMs(int maxIdleTimeMs) {
        _maxIdleTimeMs = maxIdleTimeMs;
    }

    /* ------------------------------------------------------------ */
    public void setAttribute(String name, Object value) {
        _attributes.put(name, value);
    }

    /* ------------------------------------------------------------ */
    public Object getAttribute(String name) {
        return _attributes.get(name);
    }

    /* ------------------------------------------------------------ */
    public boolean isStarted() {
        return _running > 0 && _pondLife != null;
    }

    /* ------------------------------------------------------------ */
    public int size() {
        return _size;
    }

    /* ------------------------------------------------------------ */
    public int available() {
        return _available;
    }

    /* ------------------------------------------------------------ */
    public void start() throws Exception {
        synchronized (this) {
            _running++;
            if (_running > 1)
                return;

            if (_min >= _max || _max < 1)
                throw new IllegalStateException("!(0<=min<max)");

            // Start the threads
            _pondLife = new PondLife[_max];
            _index = new int[_max];
            _size = 0;
            _available = 0;

            for (int i = 0; i < _max; i++)
                _index[i] = i;
            for (int i = 0; i < _min; i++)
                newPondLife();
        }
    }

    /* ------------------------------------------------------------ */
    public void stop() throws InterruptedException {
        synchronized (this) {
            _running--;
            if (_running > 0)
                return;
            notifyAll();
        }

        if (_pondLife != null && _size > 0) {
            for (int i = 0; i < _pondLife.length; i++)
                closePondLife(i);
            Thread.yield();
            for (int i = 0; i < _pondLife.length; i++)
                stopPondLife(i);
        }

        synchronized (this) {
            _pondLife = null;
            _index = null;
            _size = 0;
            _available = 0;
        }
    }

    /* ------------------------------------------------------------ */
    public PondLife get(int timeoutMs) throws Exception {
        PondLife pl = null;

        // Defer to other threads before locking 
        if (_available < _min)
            Thread.yield();

        int new_id = -1;

        // Try to get pondlife without creating new one.
        synchronized (this) {
            // Wait if none available.
            if (_running > 0 && _available == 0 && _size == _pondLife.length && timeoutMs > 0)
                wait(timeoutMs);

            // If still running
            if (_running > 0) {
                // if pondlife available
                if (_available > 0) {
                    int id = _index[--_available];
                    pl = _pondLife[id];
                } else if (_size < _pondLife.length) {
                    // Reserve spot for a new one
                    new_id = reservePondLife(false);
                }
            }

            // create reserved pondlife
            if (pl == null && new_id >= 0)
                pl = newPondLife(new_id);
        }

        return pl;
    }

    /* ------------------------------------------------------------ */
    public void put(PondLife pl) throws InterruptedException {
        int id = pl.getID();

        synchronized (this) {
            if (_running == 0)
                stopPondLife(id);
            else if (_pondLife[id] != null) {
                _index[_available++] = id;
                notify();
            }
        }

    }

    /* ------------------------------------------------------------ */
    public void shrink() throws InterruptedException {
        if (_running == 0)
            return;

        synchronized (this) {
            // If we have a maxIdleTime, then only shrink once per period.
            if (_maxIdleTimeMs > 0) {
                long now = System.currentTimeMillis();
                if ((now - _lastShrink) < _maxIdleTimeMs)
                    return; // don't shrink
                _lastShrink = now;
            }

            // shrink if we are running and have available threads and we are above minimal size
            if (_running > 0 && _available > 0 && _size > _min)
                stopPondLife(_index[--_available]);
        }
    }

    /* ------------------------------------------------------------ */
    private int reservePondLife(boolean available) throws Exception {
        int id = -1;
        synchronized (this) {
            id = _index[_size++];
            if (available)
                _index[_available++] = id;
        }
        return id;
    }

    /* ------------------------------------------------------------ */
    private PondLife newPondLife(int id) throws Exception {
        PondLife pl = (PondLife) _class.newInstance();
        _pondLife[id] = pl;
        pl.enterPool(this, id);
        return pl;
    }

    /* ------------------------------------------------------------ */
    private PondLife newPondLife() throws Exception {
        return newPondLife(reservePondLife(true));
    }

    /* ------------------------------------------------------------ */
    private void closePondLife(int id) {
        if (_pondLife[id] != null)
            _pondLife[id].poolClosing();
    }

    /* ------------------------------------------------------------ */
    private void stopPondLife(int id) {
        PondLife pl = null;
        synchronized (this) {
            pl = _pondLife[id];
            if (pl != null) {
                _pondLife[id] = null;
                _index[--_size] = id;
                if (_available > _size)
                    _available = _size;
            }
        }
        if (pl != null)
            pl.leavePool();
    }

    /* ------------------------------------------------------------ */
    public void dump(String msg) {
        StringBuffer pond = new StringBuffer();
        StringBuffer avail = new StringBuffer();
        StringBuffer index = new StringBuffer();

        pond.append("pond: ");
        avail.append("avail:");
        index.append("index:");

        for (int i = 0; i < _pondLife.length; i++) {
            if (_pondLife[i] == null)
                pond.append("   ");
            else {
                pond.append(' ');
                StringUtil.append(pond, (byte) i, 16);
            }

            if (i == _size)
                avail.append(i == _available ? " AS" : "  S");
            else
                avail.append(i == _available ? " A " : "   ");

            index.append(' ');
            StringUtil.append(index, (byte) _index[i], 16);
        }

        System.err.println();
        System.err.println(msg);
        System.err.println(pond);
        System.err.println(avail);
        System.err.println(index);
    }

    /* ------------------------------------------------------------ */
    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
        in.defaultReadObject();
        if (_class == null || !_class.getName().equals(_className)) {
            try {
                setPoolClass(Loader.loadClass(Pool.class, _className));
            } catch (Exception e) {
                log.warn(LogSupport.EXCEPTION, e);
                throw new java.io.InvalidObjectException(e.toString());
            }
        }
    }
}