package org.jboss.ejb.plugins;
import java.rmi.RemoteException;
import java.util.LinkedList;
import java.lang.reflect.UndeclaredThrowableException;
import javax.ejb.EJBException;
import javax.ejb.CreateException;
import org.jboss.ejb.Container;
import org.jboss.ejb.InstancePool;
import org.jboss.ejb.EnterpriseContext;
import org.jboss.deployment.DeploymentException;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.XmlLoadable;
import org.jboss.system.ServiceMBeanSupport;
import org.w3c.dom.Element;
import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
public abstract class AbstractInstancePool
extends ServiceMBeanSupport
implements AbstractInstancePoolMBean, InstancePool, XmlLoadable
{
private FIFOSemaphore strictMaxSize;
private long strictTimeout = Long.MAX_VALUE;
protected Container container;
protected LinkedList pool = new LinkedList();
protected int maxSize = 30;
protected boolean reclaim = false;
public void setContainer(Container c)
{
this.container = c;
}
public Container getContainer()
{
return container;
}
public int getCurrentSize()
{
synchronized (pool)
{
return this.pool.size();
}
}
public int getMaxSize()
{
return this.maxSize;
}
public long getAvailableCount()
{
long size = Long.MAX_VALUE;
if( strictMaxSize != null )
size = strictMaxSize.permits();
return size;
}
public EnterpriseContext get()
throws Exception
{
boolean trace = log.isTraceEnabled();
if( trace )
log.trace("Get instance "+this+"#"+pool.size()+"#"+getContainer().getBeanClass());
if( strictMaxSize != null )
{
boolean acquired = strictMaxSize.attempt(strictTimeout);
if( trace )
log.trace("Acquired("+acquired+") strictMaxSize semaphore, remaining="+strictMaxSize.permits());
if( acquired == false )
throw new EJBException("Failed to acquire the pool semaphore, strictTimeout="+strictTimeout);
}
synchronized (pool)
{
if ( pool.isEmpty() == false )
{
return (EnterpriseContext) pool.removeFirst();
}
}
try
{
Object instance = container.createBeanClassInstance();
return create(instance);
}
catch (Throwable e)
{
if( strictMaxSize != null )
{
strictMaxSize.release();
}
if( e instanceof CreateException )
throw (CreateException) e;
Exception ex = null;
if( (e instanceof Exception) == false )
{
ex = new UndeclaredThrowableException(e);
}
throw new EJBException("Could not instantiate bean", ex);
}
}
public void free(EnterpriseContext ctx)
{
if( log.isTraceEnabled() )
{
String msg = pool.size() + "/" + maxSize+" Free instance:"+this
+"#"+ctx.getId()
+"#"+ctx.getTransaction()
+"#"+reclaim
+"#"+getContainer().getBeanClass();
log.trace(msg);
}
ctx.clear();
try
{
synchronized (pool)
{
if (pool.size() < maxSize)
{
pool.addFirst(ctx);
} }
if( strictMaxSize != null )
strictMaxSize.release();
}
catch (Exception ignored)
{
}
}
public void discard(EnterpriseContext ctx)
{
if( log.isTraceEnabled() )
{
String msg = "Discard instance:"+this+"#"+ctx
+"#"+ctx.getTransaction()
+"#"+reclaim
+"#"+getContainer().getBeanClass();
log.trace(msg);
}
if( strictMaxSize != null )
strictMaxSize.release();
try
{
ctx.discard();
}
catch (RemoteException e)
{
if( log.isTraceEnabled() )
log.trace("Ctx.discard error", e);
}
}
public void importXml(Element element) throws DeploymentException
{
String maximumSize = MetaData.getElementContent(MetaData.getUniqueChild(element, "MaximumSize"));
try
{
this.maxSize = Integer.parseInt(maximumSize);
}
catch (NumberFormatException e)
{
throw new DeploymentException("Invalid MaximumSize value for instance pool configuration");
}
String strictValue = MetaData.getElementContent(MetaData.getOptionalChild(element, "strictMaximumSize"));
Boolean strictFlag = Boolean.valueOf(strictValue);
if( strictFlag == Boolean.TRUE )
this.strictMaxSize = new FIFOSemaphore(this.maxSize);
String delay = MetaData.getElementContent(MetaData.getOptionalChild(element, "strictTimeout"));
try
{
if( delay != null )
this.strictTimeout = Long.parseLong(delay);
}
catch (NumberFormatException e)
{
throw new DeploymentException("Invalid strictTimeout value for instance pool configuration");
}
}
protected abstract EnterpriseContext create(Object instance)
throws Exception;
protected void destroyService() throws Exception
{
freeAll();
this.container = null;
}
private void freeAll()
{
LinkedList clone = (LinkedList)pool.clone();
for (int i = 0; i < clone.size(); i++)
{
EnterpriseContext ec = (EnterpriseContext)clone.get(i);
ec.clear();
discard(ec);
}
pool.clear();
}
}