net.lightbody.bmp.proxy.jetty.util.Pool Maven / Gradle / Ivy
// ========================================================================
// $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.
*
* @version $Id: Pool.java,v 1.13 2005/08/13 00:01:28 gregwilkins Exp $
* @author Juancarlo Añez
* @author Greg Wilkins
*/
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<=min0)
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());
}
}
}
}