package org.jboss.ejb.plugins;
import java.lang.reflect.Constructor;
import java.rmi.NoSuchObjectException;
import java.rmi.RemoteException;
import java.util.Map;
import org.jboss.deployment.DeploymentException;
import org.jboss.ejb.BeanLock;
import org.jboss.ejb.BeanLockExt;
import org.jboss.ejb.Container;
import org.jboss.ejb.EnterpriseContext;
import org.jboss.ejb.InstanceCache;
import org.jboss.logging.Logger;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.XmlLoadable;
import org.jboss.monitor.MetricsConstants;
import org.jboss.monitor.Monitorable;
import org.jboss.monitor.client.BeanCacheSnapshot;
import org.jboss.util.CachePolicy;
import org.w3c.dom.Element;
public abstract class AbstractInstanceCache
implements InstanceCache, XmlLoadable, Monitorable, MetricsConstants,
AbstractInstanceCacheMBean
{
protected static Logger log = Logger.getLogger(AbstractInstanceCache.class);
private CachePolicy m_cache;
private final Object m_cacheLock = new Object();
public void sample(Object s)
{
if( m_cache == null )
return;
synchronized (getCacheLock())
{
BeanCacheSnapshot snapshot = (BeanCacheSnapshot)s;
snapshot.m_passivatingBeans = 0;
CachePolicy policy = getCache();
if (policy instanceof Monitorable)
{
((Monitorable)policy).sample(s);
}
}
}
public Map retrieveStatistic()
{
return null;
}
public void resetStatistic()
{
}
public EnterpriseContext get(Object id)
throws RemoteException, NoSuchObjectException
{
if (id == null) throw new IllegalArgumentException("Can't get an object with a null key");
EnterpriseContext ctx;
synchronized (getCacheLock())
{
CachePolicy cache = getCache();
ctx = (EnterpriseContext)cache.get(id);
if (ctx == null)
{
try
{
ctx = acquireContext();
setKey(id, ctx);
if (doActivate(ctx) == false)
return ctx;
logActivation(id);
cache.insert(id, ctx);
}
catch (Throwable x)
{
log.debug("Activation failure", x);
throw new NoSuchObjectException(x.getMessage());
}
}
}
return ctx;
}
public void insert(EnterpriseContext ctx)
{
if (ctx == null) throw new IllegalArgumentException("Can't insert a null object in the cache");
Object key = getKey(ctx);
synchronized (getCacheLock())
{
getCache().insert(key, ctx);
}
}
protected void tryToPassivate(EnterpriseContext ctx)
{
Object id = ctx.getId();
if (id == null) return;
BeanLock lock = getContainer().getLockManager().getLock(id);
boolean lockedBean = false;
try
{
if( lock instanceof BeanLockExt )
{
BeanLockExt lock2 = (BeanLockExt) lock;
lockedBean = lock2.attemptSync();
if( lockedBean == false )
{
log.warn("Unable to passivate due to ctx lock, id="+id);
return;
}
}
else
{
lock.sync();
lockedBean = true;
}
if (canPassivate(ctx))
{
try
{
remove(id);
passivate(ctx);
freeContext(ctx);
}
catch (Exception ignored)
{
log.warn("failed to passivate, id="+id, ignored);
}
}
else
{
log.warn("Unable to passivate due to ctx lock, id="+id);
synchronized (getCacheLock())
{
getCache().get(id);
}
}
}
finally
{
if( lockedBean )
lock.releaseSync();
getContainer().getLockManager().removeLockRef(id);
}
}
public void release(EnterpriseContext ctx)
{
if (ctx == null) throw new IllegalArgumentException("Can't release a null object");
Object id = getKey(ctx);
synchronized (getCacheLock())
{
if (getCache().peek(id) != null)
getCache().remove(id);
}
tryToPassivate(ctx);
}
public void remove(Object id)
{
if (id == null) throw new IllegalArgumentException("Can't remove an object using a null key");
synchronized (getCacheLock())
{
if (getCache().peek(id) != null)
{
getCache().remove(id);
}
}
}
public boolean isActive(Object id)
{
synchronized (getCacheLock())
{
return getCache().peek(id) != null;
}
}
public long getCacheSize()
{
int cacheSize = m_cache != null ? m_cache.size() : 0;
return cacheSize;
}
public void flush()
{
if( m_cache != null )
m_cache.flush();
}
public long getPassivatedCount()
{
return 0;
}
public String getCachePolicyString()
{
return m_cache.toString();
}
public void importXml(Element element) throws DeploymentException
{
String p = MetaData.getElementContent(MetaData.getUniqueChild(element, "cache-policy"));
try
{
Class cls = SecurityActions.getContextClassLoader().loadClass(p);
Constructor ctor = cls.getConstructor(new Class[] {AbstractInstanceCache.class});
m_cache = (CachePolicy)ctor.newInstance(new Object[] {this});
}
catch (Exception x)
{
throw new DeploymentException("Can't create cache policy", x);
}
Element policyConf = MetaData.getOptionalChild(element, "cache-policy-conf");
if (policyConf != null)
{
if (m_cache instanceof XmlLoadable)
{
try
{
((XmlLoadable)m_cache).importXml(policyConf);
}
catch (Exception x)
{
throw new DeploymentException("Can't import policy configuration", x);
}
}
}
}
public void create() throws Exception
{
getCache().create();
}
public void start() throws Exception
{
getCache().start();
}
public void stop()
{
synchronized (getCacheLock())
{
getCache().stop();
}
}
public void destroy()
{
synchronized (getCacheLock())
{
getCache().destroy();
}
this.m_cache = null;
}
protected void logActivation(Object id)
{
if( log.isTraceEnabled() )
{
StringBuffer m_buffer=new StringBuffer(100);
m_buffer.append("Activated bean ");
m_buffer.append(getContainer().getBeanMetaData().getEjbName());
m_buffer.append(" with id = ");
m_buffer.append(id);
log.trace(m_buffer.toString());
}
}
protected void logPassivation(Object id)
{
if( log.isTraceEnabled() )
{
StringBuffer m_buffer=new StringBuffer(100);
m_buffer.append("Passivated bean ");
m_buffer.append(getContainer().getBeanMetaData().getEjbName());
m_buffer.append(" with id = ");
m_buffer.append(id);
log.trace(m_buffer.toString());
}
}
protected abstract Container getContainer();
protected CachePolicy getCache() {return m_cache;}
public Object getCacheLock()
{
return m_cacheLock;
}
protected abstract void passivate(EnterpriseContext ctx) throws RemoteException;
protected abstract void activate(EnterpriseContext ctx) throws RemoteException;
protected boolean doActivate(EnterpriseContext ctx) throws RemoteException
{
activate(ctx);
return true;
}
protected abstract EnterpriseContext acquireContext() throws Exception;
protected abstract void freeContext(EnterpriseContext ctx);
protected abstract Object getKey(EnterpriseContext ctx);
protected abstract void setKey(Object id, EnterpriseContext ctx);
protected abstract boolean canPassivate(EnterpriseContext ctx);
}