[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