[jboss-cvs] JBossAS SVN: r60647 - branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Mon Feb 19 03:53:49 EST 2007
Author: bstansberry at jboss.com
Date: 2007-02-19 03:53:49 -0500 (Mon, 19 Feb 2007)
New Revision: 60647
Modified:
branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java
Log:
[EJBTHREE-867] Loosen coupling of lifecycle of nested SFSBs
[EJBTHREE-849] Properly handle passivation/activation callbacks for nested SFSBs
[EJBTHREE-851] Invoke passivation/activation callbacks around replication
[EJBTHREE-846] Transfer passivated sessions on startup
[EJBTHREE-856] Add gravitation call needed for buddy replication
Modified: branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java
===================================================================
--- branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java 2007-02-19 08:53:22 UTC (rev 60646)
+++ branches/Branch_4_2/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java 2007-02-19 08:53:49 UTC (rev 60647)
@@ -21,6 +21,7 @@
*/
package org.jboss.ejb3.cache.tree;
+import java.lang.ref.WeakReference;
import java.util.Set;
import javax.ejb.EJBException;
@@ -32,6 +33,7 @@
import org.jboss.cache.xml.XmlHelper;
import org.jboss.cache.eviction.RegionManager;
import org.jboss.cache.eviction.Region;
+import org.jboss.cache.marshall.RegionNotFoundException;
import org.jboss.cache.CacheException;
import org.jboss.cache.AbstractTreeCacheListener;
import org.jboss.cache.DataNode;
@@ -41,6 +43,7 @@
import org.jboss.ejb3.EJBContainer;
import org.jboss.ejb3.Pool;
import org.jboss.ejb3.cache.ClusteredStatefulCache;
+import org.jboss.ejb3.stateful.NestedStatefulBeanContext;
import org.jboss.ejb3.stateful.ProxiedStatefulBeanContext;
import org.jboss.ejb3.stateful.StatefulBeanContext;
import org.jboss.mx.util.MBeanProxyExt;
@@ -60,10 +63,19 @@
*/
public class StatefulTreeCache implements ClusteredStatefulCache
{
- protected static Logger log = Logger.getLogger(StatefulTreeCache.class);
- static int FQN_SIZE = 2; // depth of fqn that we store the session in.
-
+ private static final int FQN_SIZE = 2; // depth of fqn that we store the session in.
+
+ private static Option LOCAL_ONLY_OPTION = new Option();
+ private static Option GRAVITATE_OPTION = new Option();
+ static
+ {
+ LOCAL_ONLY_OPTION.setCacheModeLocal(true);
+ GRAVITATE_OPTION.setForceDataGravitation(true);
+ }
+
+ private Logger log = Logger.getLogger(StatefulTreeCache.class);
private Pool pool;
+ private WeakReference<ClassLoader> classloader;
private TreeCache cache;
private Fqn cacheNode;
private ClusteredStatefulCacheListener listener;
@@ -78,8 +90,12 @@
try
{
ctx = (StatefulBeanContext) pool.get();
- cache.put(new Fqn(cacheNode, ctx.getId().toString()), "bean", ctx);
- ctx.inUse = true;
+ if (log.isTraceEnabled())
+ {
+ log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass());
+ }
+ putInCache(ctx);
+ ctx.setInUse(true);
ctx.lastUsed = System.currentTimeMillis();
++createCount;
}
@@ -100,9 +116,12 @@
try
{
ctx = (StatefulBeanContext) pool.get(initTypes, initValues);
- Fqn id = new Fqn(cacheNode, ctx.getId().toString());
- cache.put(id, "bean", ctx);
- ctx.inUse = true;
+ if (log.isTraceEnabled())
+ {
+ log.trace("Caching context " + ctx.getId() + " of type " + ctx.getClass());
+ }
+ putInCache(ctx);
+ ctx.setInUse(true);
ctx.lastUsed = System.currentTimeMillis();
++createCount;
}
@@ -119,37 +138,57 @@
public StatefulBeanContext get(Object key) throws EJBException
{
+ return get(key, true);
+ }
+
+ public StatefulBeanContext get(Object key, boolean markInUse) throws EJBException
+ {
StatefulBeanContext entry = null;
Fqn id = new Fqn(cacheNode, key.toString());
try
{
- Object obj = cache.get(id, "bean");
- entry = (StatefulBeanContext) obj;
+ Option opt = new Option();
+ opt.setForceDataGravitation(true);
+ entry = (StatefulBeanContext) cache.get(id, "bean", opt);
}
catch (CacheException e)
{
RuntimeException re = convertToRuntimeException(e);
throw re;
}
+
if (entry == null)
{
- throw new NoSuchEJBException("Could not find Stateful bean: " + key);
+ throw new NoSuchEJBException("Could not find stateful bean: " + key);
}
- entry.inUse = true;
- // Mark it to eviction thread that don't passivate it yet.
- evictRegionManager.markNodeCurrentlyInUse(id, MarkInUseWaitTime);
- entry.lastUsed = System.currentTimeMillis();
+ else if (markInUse && entry.isRemoved())
+ {
+ throw new NoSuchEJBException("Could not find stateful bean: " + key +
+ " (bean was marked as removed)");
+ }
+ entry.postReplicate();
+
+ if (markInUse)
+ {
+ entry.setInUse(true);
+
+ // Mark the Fqn telling the eviction thread not to passivate it yet.
+ // Note the Fqn we use is relative to the region!
+ evictRegionManager.markNodeCurrentlyInUse(id, MarkInUseWaitTime);
+ entry.lastUsed = System.currentTimeMillis();
+ }
+
if(log.isTraceEnabled())
{
log.trace("get: retrieved bean with cache id " +id.toString());
}
+
return entry;
}
public void remove(Object key)
{
- StatefulBeanContext ctx = null;
Fqn id = new Fqn(cacheNode, key.toString());
try
{
@@ -157,21 +196,32 @@
{
log.trace("remove: cache id " +id.toString());
}
- cache.remove(id);
+
+ Option opt = new Option();
+ opt.setForceDataGravitation(true);
+ StatefulBeanContext ctx = (StatefulBeanContext) cache.get(id, "bean", opt);
+
+ if (ctx != null)
+ {
+ if (!ctx.isRemoved())
+ pool.remove(ctx);
+
+ if (ctx.getCanRemoveFromCache())
+ cache.remove(id);
+ }
}
catch (CacheException e)
{
RuntimeException re = convertToRuntimeException(e);
throw re;
}
- if (ctx != null) pool.remove(ctx);
}
public void finished(StatefulBeanContext ctx)
{
synchronized (ctx)
{
- ctx.inUse = false;
+ ctx.setInUse(false);
ctx.lastUsed = System.currentTimeMillis();
Fqn id = new Fqn(cacheNode, ctx.getId().toString());
// OK, it is free to passivate now.
@@ -181,21 +231,17 @@
public void replicate(StatefulBeanContext ctx)
{
+ // StatefulReplicationInterceptor should only pass us the ultimate
+ // parent context for a tree of nested beans, which should always be
+ // a standard StatefulBeanContext
+ if (ctx instanceof NestedStatefulBeanContext)
+ {
+ throw new IllegalArgumentException("Received unexpected replicate call for nested context " + ctx.getId());
+ }
+
try
{
- // Don't replicate proxies, as they are in the cache
- // as elements of their containing bean context
- // TODO -- if this is a ProxiedStatefulBeanContext
- // should we replicate the parent context, since that's where
- // the data is?
- if (!(ctx instanceof ProxiedStatefulBeanContext))
- {
- cache.put(new Fqn(cacheNode, ctx.getId().toString()), "bean", ctx);
- }
- else if (log.isTraceEnabled())
- {
- log.trace("replicate(): ignoring replicate call for proxy to " + ctx.getId());
- }
+ putInCache(ctx);
}
catch (CacheException e)
{
@@ -206,8 +252,13 @@
public void initialize(Container container) throws Exception
{
+ log = Logger.getLogger(getClass().getName() + "." + container.getEjbName());
+
+ this.pool = container.getPool();
+ ClassLoader cl = ((EJBContainer) container).getClassloader();
+ this.classloader = new WeakReference<ClassLoader>(cl);
+
Advisor advisor = (Advisor) container;
- this.pool = container.getPool();
CacheConfig config = (CacheConfig) advisor.resolveAnnotation(CacheConfig.class);
MBeanServer server = MBeanServerLocator.locateJBoss();
ObjectName cacheON = new ObjectName(config.name());
@@ -221,11 +272,15 @@
Element element = getElementConfig(cacheNode.toString(), config.idleTimeoutSeconds(),
config.maxSize());
Region region = evictRegionManager.createRegion(cacheNode, element);
+
+ cache.registerClassLoader(cacheNode.toString(), cl);
+ cache.activateRegion(cacheNode.toString());
+
log.debug("initialize(): create eviction region: " +region + " for ejb: " +container.getEjbName());
}
protected Element getElementConfig(String regionName, long timeToLiveSeconds, int maxNodes) throws Exception {
- String xml = "<region name=\"" +regionName +"\" policyClass=\"org.jboss.cache.eviction.LRUPolicy\">\n" +
+ String xml = "<region name=\"" +regionName +"\" policyClass=\"org.jboss.ejb3.cache.tree.AbortableLRUPolicy\">\n" +
"<attribute name=\"maxNodes\">" +maxNodes +"</attribute>\n" +
"<attribute name=\"timeToLiveSeconds\">"+ timeToLiveSeconds +"</attribute>\n" +
"</region>";
@@ -247,30 +302,40 @@
{
// Remove the listener
cache.removeTreeCacheListener(listener);
-
- // BES 11/16/2006 uncomment if we switch to per-region marshalling
- // If we do, we don't need to remove the node below; deactivate() does it
-// if (region != null)
-// {
-// region.deactivate();
-// region.unregisterContextClassLoader();
-// }
- // Remove the eviction region
- RegionManager rm = cache.getEvictionRegionManager();
- rm.removeRegion(cacheNode);
-
- Option opt = new Option();
- opt.setCacheModeLocal(true);
try {
- // remove locally.
+ // Remove locally. We do this to clean up the persistent store,
+ // which is not affected by the inactivateRegion call below.
+ Option opt = new Option();
+ opt.setCacheModeLocal(true);
cache.remove(cacheNode, opt);
}
catch (CacheException e)
{
log.error("Stop(): can't remove bean from the underlying distributed cache");
+ }
+
+ try
+ {
+ cache.inactivateRegion(cacheNode.toString());
}
+ catch (Exception e)
+ {
+ log.error("Caught exception inactivating region " + cacheNode, e);
+ }
+ try
+ {
+ cache.unregisterClassLoader(cacheNode.toString());
+ }
+ catch (RegionNotFoundException e)
+ {
+ log.error("Caught exception unregistering classloader from region " + cacheNode, e);
+ }
+ // Remove the eviction region
+ RegionManager rm = cache.getEvictionRegionManager();
+ rm.removeRegion(cacheNode);
+
log.debug("stop(): StatefulTreeCache stopped successfully for " +cacheNode);
}
@@ -297,6 +362,13 @@
return passivatedCount;
}
+ private void putInCache(StatefulBeanContext ctx) throws CacheException
+ {
+ ctx.preReplicate();
+ cache.put(new Fqn(cacheNode, ctx.getId().toString()), "bean", ctx);
+ ctx.markedForReplication = false;
+ }
+
/**
* Creates a RuntimeException, but doesn't pass CacheException as the cause
* as it is a type that likely doesn't exist on a client.
@@ -316,8 +388,6 @@
*/
public class ClusteredStatefulCacheListener extends AbstractTreeCacheListener
{
- protected Logger log = Logger.getLogger(ClusteredStatefulCacheListener.class);
-
@Override
public void nodeActivate(Fqn fqn, boolean pre)
{
@@ -346,10 +416,24 @@
if(log.isTraceEnabled())
{
- log.trace("nodeActivate(): sending postActivate event on fqn: " +fqn);
+ log.trace("nodeActivate(): sending postActivate event to bean at fqn: " +fqn);
}
-
- bean.postActivate();
+
+ ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
+ try
+ {
+ ClassLoader cl = classloader.get();
+ if (cl != null)
+ {
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
+ bean.activateAfterReplication();
+ }
+ finally
+ {
+ Thread.currentThread().setContextClassLoader(oldCl);
+ }
}
@Override
@@ -374,23 +458,33 @@
bean = (StatefulBeanContext) node.get("bean");
if (bean != null)
{
- if (bean.inUse)
+ ClassLoader cl = classloader.get();
+ if (cl != null)
{
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+
+ if (!bean.getCanPassivate())
+ {
// Abort the eviction
- throw new IllegalStateException("Cannot passivate bean " + fqn + " -- it is currently in use");
+ throw new ContextInUseException("Cannot passivate bean " + fqn +
+ " -- it or one if its children is currently in use");
}
+
if(log.isTraceEnabled())
{
log.trace("nodePassivate(): send prePassivate event to bean at fqn: " +fqn);
}
- Thread.currentThread().setContextClassLoader(((EJBContainer) bean.getContainer()).getClassloader());
- bean.prePassivate();
+
+ bean.passivateAfterReplication();
++passivatedCount;
}
}
}
catch (NoSuchEJBException e)
{
+ // TODO is this still necessary? Don't think we
+ // should have orphaned proxies any more
if (bean instanceof ProxiedStatefulBeanContext)
{
// This is probably an orphaned proxy; double check and remove it
More information about the jboss-cvs-commits
mailing list