[jboss-cvs] JBossAS SVN: r61333 - in trunk/ejb3/src: main/org/jboss/annotation/ejb/cache/tree and 9 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Mar 14 21:13:03 EDT 2007


Author: bdecoste
Date: 2007-03-14 21:13:03 -0400 (Wed, 14 Mar 2007)
New Revision: 61333

Added:
   trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulClusteredTimeoutBean.java
   trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeout.java
   trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeoutBean.java
Modified:
   trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfig.java
   trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfigImpl.java
   trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfig.java
   trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfigImpl.java
   trunk/ejb3/src/main/org/jboss/ejb3/EJBContainer.java
   trunk/ejb3/src/main/org/jboss/ejb3/Ejb3DescriptorHandler.java
   trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java
   trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionFilePersistenceManager.java
   trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionPersistenceManager.java
   trunk/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java
   trunk/ejb3/src/main/org/jboss/ejb3/metamodel/CacheConfig.java
   trunk/ejb3/src/main/org/jboss/ejb3/metamodel/JBossDDObjectFactory.java
   trunk/ejb3/src/main/org/jboss/ejb3/stateful/StatefulBeanContext.java
   trunk/ejb3/src/resources/ejb3-interceptors-aop.xml
   trunk/ejb3/src/resources/test/stateful/META-INF/ejb-jar.xml
   trunk/ejb3/src/resources/test/stateful/META-INF/jboss.xml
   trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/unit/RemoteUnitTestCase.java
Log:
[EJBTHREE-904]merged from 4.2. SFSB removal timeout

Modified: trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfig.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfig.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfig.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -39,4 +39,6 @@
    int maxSize() default 100000;
 
    long idleTimeoutSeconds() default 300;
+   
+   long removalTimeoutSeconds() default 0;
 }

Modified: trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfigImpl.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfigImpl.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/simple/CacheConfigImpl.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -31,6 +31,7 @@
 {
    private int maxSize = 100000;
    private long idleTimeoutSeconds = 300;
+   private long removalTimeoutSeconds = 0;
 
    public CacheConfigImpl()
    {
@@ -55,6 +56,29 @@
    {
       this.idleTimeoutSeconds = idleTimeoutSeconds;
    }
+   
+   public long removalTimeoutSeconds()
+   {
+      return removalTimeoutSeconds;
+   }
+   
+   public void setRemovalTimeoutSeconds(long removalTimeoutSeconds)
+   {
+      this.removalTimeoutSeconds = removalTimeoutSeconds;
+   }
+   
+   public void merge(CacheConfig annotation)
+   {   
+      if (maxSize == 100000)
+         maxSize = annotation.maxSize();
+      
+      if (idleTimeoutSeconds == 300)
+         idleTimeoutSeconds = annotation.idleTimeoutSeconds();
+      
+      if (removalTimeoutSeconds == 0)
+         removalTimeoutSeconds = annotation.removalTimeoutSeconds();
+      
+   }
 
    public Class<? extends Annotation> annotationType()
    {

Modified: trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfig.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfig.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfig.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -43,4 +43,6 @@
    long idleTimeoutSeconds() default 300;
    
    boolean replicationIsPassivation() default true;
+   
+   long removalTimeoutSeconds() default 0;
 }

Modified: trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfigImpl.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfigImpl.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/annotation/ejb/cache/tree/CacheConfigImpl.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -32,6 +32,7 @@
    private String name = "jboss.cache:service=EJB3SFSBClusteredCache";
    private int maxSize = 100000;
    private long idleTimeoutSeconds = 300;
+   private long removalTimeoutSeconds = 0;
    private boolean replicationIsPassivation = true;
    
    public CacheConfigImpl()
@@ -67,6 +68,16 @@
    {
       this.idleTimeoutSeconds = idleTimeoutSeconds;
    }
+   
+   public long removalTimeoutSeconds()
+   {
+      return removalTimeoutSeconds;
+   }
+   
+   public void setRemovalTimeoutSeconds(long removalTimeoutSeconds)
+   {
+      this.removalTimeoutSeconds = removalTimeoutSeconds;
+   }
 
    public boolean replicationIsPassivation()
    {
@@ -77,6 +88,22 @@
    {
       this.replicationIsPassivation = replicationIsPassivation;
    }
+   
+   public void merge(CacheConfig annotation)
+   {   
+      if (maxSize == 100000)
+         maxSize = annotation.maxSize();
+      
+      if (idleTimeoutSeconds == 300)
+         idleTimeoutSeconds = annotation.idleTimeoutSeconds();
+      
+      if (removalTimeoutSeconds == 0)
+         removalTimeoutSeconds = annotation.removalTimeoutSeconds();
+      
+      if (replicationIsPassivation == true)
+         replicationIsPassivation = annotation.replicationIsPassivation();
+      
+   }
 
    public Class<? extends Annotation> annotationType()
    {

Modified: trunk/ejb3/src/main/org/jboss/ejb3/EJBContainer.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/EJBContainer.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/EJBContainer.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -533,8 +533,11 @@
    {
       encFactory.cleanupEnc(this);
       
-      pool.destroy();
-      pool = null;
+      if (pool != null)
+      {
+         pool.destroy();
+         pool = null;
+      }
       
       log.info("STOPPED EJB: " + clazz.getName() + " ejbName: " + ejbName);
    }

Modified: trunk/ejb3/src/main/org/jboss/ejb3/Ejb3DescriptorHandler.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/Ejb3DescriptorHandler.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/Ejb3DescriptorHandler.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -1301,6 +1301,13 @@
             if (config.getReplicationIsPassivation() != null)
                configAnnotation.setReplicationIsPassivation(Boolean.parseBoolean(config.getReplicationIsPassivation()));
 
+            if (config.getRemoveTimeoutSeconds() != null)
+               configAnnotation.setRemovalTimeoutSeconds(Long.parseLong(config.getRemoveTimeoutSeconds()));
+            
+            org.jboss.annotation.ejb.cache.tree.CacheConfig existingConfig = (org.jboss.annotation.ejb.cache.tree.CacheConfig)ejbClass.getAnnotation(org.jboss.annotation.ejb.cache.tree.CacheConfig.class);
+            if (existingConfig != null)
+               configAnnotation.merge(existingConfig);
+            
             addClassAnnotation(container, org.jboss.annotation.ejb.cache.tree.CacheConfig.class, configAnnotation);
          }
          else
@@ -1312,7 +1319,14 @@
 
             if (config.getIdleTimeoutSeconds() != null)
                configAnnotation.setIdleTimeoutSeconds(Long.parseLong(config.getIdleTimeoutSeconds()));
+            
+            if (config.getRemoveTimeoutSeconds() != null)
+               configAnnotation.setRemovalTimeoutSeconds(Long.parseLong(config.getRemoveTimeoutSeconds()));
 
+            org.jboss.annotation.ejb.cache.simple.CacheConfig existingConfig = (org.jboss.annotation.ejb.cache.simple.CacheConfig)ejbClass.getAnnotation(org.jboss.annotation.ejb.cache.simple.CacheConfig.class);
+            if (existingConfig != null)
+               configAnnotation.merge(existingConfig);
+            
             addClassAnnotation(container, org.jboss.annotation.ejb.cache.simple.CacheConfig.class, configAnnotation);
          }
       }

Modified: trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/SimpleStatefulCache.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -23,6 +23,7 @@
 
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import javax.ejb.EJBException;
 import javax.ejb.NoSuchEJBException;
@@ -51,8 +52,11 @@
    private int maxSize = 1000;
    private StatefulSessionPersistenceManager pm;
    private long sessionTimeout = 300; // 5 minutes
+   private long removalTimeout = 0; 
    private SessionTimeoutTask timeoutTask;
+   private RemovalTimeoutTask removalTask = null;
    private boolean running = true;
+   private Container container;
 
    private class CacheMap extends LinkedHashMap
    {
@@ -91,7 +95,70 @@
          return removeIt;
       }
    }
+   
+   private class RemovalTimeoutTask extends Thread
+   {
+      public RemovalTimeoutTask(String name)
+      {
+         super(name);
+      }
 
+      public void run()
+      {
+         while (running)
+         {
+            try
+            {
+               Thread.sleep(removalTimeout * 1000);
+            }
+            catch (InterruptedException e)
+            {
+               running = false;
+               return;
+            }
+            try
+            {
+               long now = System.currentTimeMillis();
+               
+               synchronized (cacheMap)
+               {
+                  if (!running) return;
+                   
+                  Iterator it = cacheMap.entrySet().iterator();
+                  while (it.hasNext())
+                  {
+                     Map.Entry entry = (Map.Entry) it.next();
+                     StatefulBeanContext centry = (StatefulBeanContext) entry.getValue();
+                     if (now - centry.lastUsed >= removalTimeout * 1000)
+                     {
+                        synchronized (centry)
+                        {                                                                    
+                           it.remove();
+                        }
+                     }
+                  }                  
+               }
+               
+               List<StatefulBeanContext> beans = pm.getPassivatedBeans();  
+               Iterator<StatefulBeanContext> it = beans.iterator();
+               while (it.hasNext())
+               {       
+                  StatefulBeanContext centry = it.next();
+                  if (now - centry.lastUsed >= removalTimeout * 1000)
+                  {
+                     get(centry.getId(), false);
+                     remove(centry.getId());
+                  }               
+               }
+            }
+            catch (Exception ex)
+            {
+               log.error("problem removing SFSB thread", ex);
+            }
+         }
+      }
+   }
+
    private class SessionTimeoutTask extends Thread
    {
       public SessionTimeoutTask(String name)
@@ -168,6 +235,7 @@
    public void initialize(Container container) throws Exception
    {
       Advisor advisor = (Advisor) container;
+      this.container = container;
       this.pool = container.getPool();
       cacheMap = new CacheMap();
       PersistenceManager pmConfig = (PersistenceManager) advisor.resolveAnnotation(PersistenceManager.class);
@@ -176,10 +244,14 @@
       CacheConfig config = (CacheConfig) advisor.resolveAnnotation(CacheConfig.class);
       maxSize = config.maxSize();
       sessionTimeout = config.idleTimeoutSeconds();
+      removalTimeout = config.removalTimeoutSeconds();
       log = Logger.getLogger(getClass().getName() + "." + container.getEjbName());
       log.debug("Initializing SimpleStatefulCache with maxSize: " +maxSize + " timeout: " +sessionTimeout +
               " for " +container.getObjectName().getCanonicalName() );
       timeoutTask = new SessionTimeoutTask("SFSB Passivation Thread - " + container.getObjectName().getCanonicalName());
+   
+      if (removalTimeout > 0)
+         removalTask = new RemovalTimeoutTask("SFSB Removal Thread - " + container.getObjectName().getCanonicalName());
    }
 
    public SimpleStatefulCache()
@@ -190,6 +262,9 @@
    {
       running = true;
       timeoutTask.start();
+      
+      if (removalTask != null)
+         removalTask.start();
    }
 
    public void stop()
@@ -198,6 +273,8 @@
       {
          running = false;
          timeoutTask.interrupt();
+         if (removalTask != null)
+            removalTask.interrupt();
          cacheMap.clear();
          try
          {

Modified: trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionFilePersistenceManager.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionFilePersistenceManager.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionFilePersistenceManager.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -33,6 +33,10 @@
 import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+
+import java.util.List;
+import java.util.LinkedList;
+
 import javax.ejb.EJBException;
 import org.jboss.ejb3.Container;
 import org.jboss.ejb3.stateful.StatefulBeanContext;
@@ -313,6 +317,40 @@
       bean.postActivate();
       return bean;
    }
+   
+   public List<StatefulBeanContext> getPassivatedBeans()
+   {
+      List beans = new LinkedList();
+      
+      File[] files = storeDir.listFiles();
+      for (File file : files)
+      {
+         try
+         {
+            ObjectInputStream in;
+            
+            FileInputStream fis = FISAction.open(file);
+   
+            in = new JBossObjectInputStream(new BufferedInputStream(fis));
+            try
+            {
+               StatefulBeanContext bean = (StatefulBeanContext) in.readObject();
+               beans.add(bean);
+            }
+            finally
+            {
+               fis.close();
+               in.close();
+            }
+         }
+         catch (Exception e)
+         {
+            log.warn("Could not read for timeout removal for file " + file.getName() + ". " + e.getMessage());
+         }
+      }
+      
+      return beans;
+   }
 
    /**
     * Invokes {@link javax.ejb.SessionBean#ejbPassivate} on the target bean and saves the

Modified: trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionPersistenceManager.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionPersistenceManager.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/cache/simple/StatefulSessionPersistenceManager.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -21,6 +21,8 @@
  */
 package org.jboss.ejb3.cache.simple;
 
+import java.util.List;
+
 import org.jboss.ejb3.Container;
 import org.jboss.ejb3.stateful.StatefulBeanContext;
 import org.jboss.logging.Logger;
@@ -50,6 +52,8 @@
     * state of the session to a file.
     */
    void passivateSession(StatefulBeanContext ctx);
+   
+   List<StatefulBeanContext> getPassivatedBeans();
 
    /**
     * Removes the saved state file (if any) for the given session id.

Modified: trunk/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/cache/tree/StatefulTreeCache.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -22,6 +22,8 @@
 package org.jboss.ejb3.cache.tree;
 
 import java.lang.ref.WeakReference;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.Iterator;
 import java.util.Map;
 
 import javax.ejb.EJBException;
@@ -81,8 +83,13 @@
    private Region region;
    private ClusteredStatefulCacheListener listener;
    
+   public static long MarkInUseWaitTime = 15000;
    
-   public static long MarkInUseWaitTime = 15000;
+   protected long removalTimeout = 0; 
+   protected RemovalTimeoutTask removalTask = null;
+   protected boolean running = true;
+   protected Map<Object, Long> beans = new ConcurrentHashMap<Object, Long>();
+   protected Container container;
 
    public StatefulBeanContext create()
    {
@@ -97,6 +104,7 @@
          putInCache(ctx);
          ctx.setInUse(true);
          ctx.lastUsed = System.currentTimeMillis();
+         beans.put(ctx.getId(), ctx.lastUsed);
       }
       catch (EJBException e)
       {
@@ -122,6 +130,7 @@
          putInCache(ctx);
          ctx.setInUse(true);
          ctx.lastUsed = System.currentTimeMillis();
+         beans.put(ctx.getId(), ctx.lastUsed);
       }
       catch (EJBException e)
       {
@@ -176,6 +185,7 @@
          // Note the Fqn we use is relative to the region!
          region.markNodeCurrentlyInUse(new Fqn(key.toString()), MarkInUseWaitTime);
          entry.lastUsed = System.currentTimeMillis();
+         beans.put(key, entry.lastUsed);
       }
       
       if(log.isTraceEnabled())
@@ -206,6 +216,8 @@
             
             if (ctx.getCanRemoveFromCache())
                cache.removeNode(id);
+            
+            beans.remove(key);
          }
       }
       catch (CacheException e)
@@ -221,6 +233,7 @@
       {
          ctx.setInUse(false);
          ctx.lastUsed = System.currentTimeMillis();
+         beans.put(ctx.getId(), ctx.lastUsed);
          // OK, it is free to passivate now.
          // Note the Fqn we use is relative to the region!
          region.unmarkNodeCurrentlyInUse(new Fqn(ctx.getId().toString()));
@@ -252,6 +265,7 @@
    {
       log = Logger.getLogger(getClass().getName() + "." + container.getEjbName());
       
+      this.container = container;
       this.pool = container.getPool();
       ClassLoader cl = ((EJBContainer) container).getClassloader();
       this.classloader = new WeakReference<ClassLoader>(cl);
@@ -276,6 +290,10 @@
       region.activate();
       
       log.debug("initialize(): created region: " +region + " for ejb: " +container.getEjbName());
+   
+      removalTimeout = config.removalTimeoutSeconds();
+      if (removalTimeout > 0)
+         removalTask = new RemovalTimeoutTask("SFSB Removal Thread - " + container.getObjectName().getCanonicalName());
    }
    
    protected EvictionPolicyConfig getEvictionPolicyConfig(int timeToLiveSeconds, int maxNodes)
@@ -297,10 +315,17 @@
       // one this event belongs to. Consider having a singleton listener
       listener = new ClusteredStatefulCacheListener();
       cache.addCacheListener(listener);
+      
+      if (removalTask != null)
+         removalTask.start();
+      
+      running = true;
    }
 
    public void stop()
    {
+      running = false;
+
       // Remove the listener
       cache.removeCacheListener(listener);
       
@@ -330,6 +355,9 @@
       
       classloader = null;
       
+      if (removalTask != null)
+         removalTask.interrupt();
+      
       log.debug("stop(): StatefulTreeCache stopped successfully for " +cacheNode);
    }
    
@@ -517,4 +545,47 @@
          throw new RuntimeException(e);
       }
    }
+   
+   private class RemovalTimeoutTask extends Thread
+   {
+      public RemovalTimeoutTask(String name)
+      {
+         super(name);
+      }
+
+      public void run()
+      {
+         while (running)
+         {
+            try
+            {
+               Thread.sleep(removalTimeout * 1000);
+            }
+            catch (InterruptedException e)
+            {
+               running = false;
+               return;
+            }
+            try
+            {
+               long now = System.currentTimeMillis();
+               
+               Iterator<Map.Entry<Object, Long>> it = beans.entrySet().iterator();
+               while (it.hasNext())
+               {
+                  Map.Entry<Object, Long> entry = it.next();
+                  long lastUsed = entry.getValue();
+                  if (now - lastUsed >= removalTimeout * 1000)
+                  {
+                     remove(entry.getKey());
+                  }
+               }
+            }
+            catch (Exception ex)
+            {
+               log.error("problem removing SFSB thread", ex);
+            }
+         }
+      }
+   }
 }

Modified: trunk/ejb3/src/main/org/jboss/ejb3/metamodel/CacheConfig.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/metamodel/CacheConfig.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/metamodel/CacheConfig.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -33,6 +33,7 @@
    private String cacheClass = null;
    private String maxSize = null;
    private String idleTimeoutSeconds = null;
+   private String removeTimeoutSeconds = null;
    private String name = null;
    private String persistenceManager = null;
    private String replicationIsPassivation = null;
@@ -77,6 +78,16 @@
       this.idleTimeoutSeconds = idleTimeoutSeconds;
    }
    
+   public String getRemoveTimeoutSeconds()
+   {
+      return removeTimeoutSeconds;
+   }
+
+   public void setRemoveTimeoutSeconds(String removeTimeoutSeconds)
+   {
+      this.removeTimeoutSeconds = removeTimeoutSeconds;
+   }
+   
    public String getName()
    {
       return name;

Modified: trunk/ejb3/src/main/org/jboss/ejb3/metamodel/JBossDDObjectFactory.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/metamodel/JBossDDObjectFactory.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/metamodel/JBossDDObjectFactory.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -985,6 +985,10 @@
       {
          config.setIdleTimeoutSeconds(getValue(localName, value));
       }
+      else if (localName.equals("remove-timeout-seconds"))
+      {
+         config.setRemoveTimeoutSeconds(getValue(localName, value));
+      }
       else if (localName.equals("cache-name"))
       {
          config.setName(getValue(localName, value));

Modified: trunk/ejb3/src/main/org/jboss/ejb3/stateful/StatefulBeanContext.java
===================================================================
--- trunk/ejb3/src/main/org/jboss/ejb3/stateful/StatefulBeanContext.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/main/org/jboss/ejb3/stateful/StatefulBeanContext.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -757,7 +757,7 @@
    // to its NestedStatefulBeanContext
    private volatile boolean inUse = false;
 
-   public volatile long lastUsed = System.currentTimeMillis();
+   public long lastUsed = System.currentTimeMillis();
 
    @Override
    public Object[] getInterceptorInstances(InterceptorInfo[] interceptorInfos)
@@ -817,7 +817,8 @@
    {
       out.writeUTF(containerName);
       out.writeObject(id);
-      out.writeObject(metadata);      
+      out.writeObject(metadata);
+      out.writeLong(lastUsed);
       
       if (beanMO == null)
       {
@@ -860,6 +861,8 @@
       containerName = in.readUTF();
       id = in.readObject();
       metadata = (SimpleMetaData) in.readObject();
+      lastUsed = in.readLong();
+      
       beanMO = (MarshalledObject) in.readObject();
       removed = in.readBoolean();
       replicationIsPassivation = in.readBoolean();

Modified: trunk/ejb3/src/resources/ejb3-interceptors-aop.xml
===================================================================
--- trunk/ejb3/src/resources/ejb3-interceptors-aop.xml	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/resources/ejb3-interceptors-aop.xml	2007-03-15 01:13:03 UTC (rev 61333)
@@ -193,7 +193,7 @@
          @org.jboss.annotation.ejb.cache.simple.PersistenceManager (org.jboss.ejb3.cache.simple.StatefulSessionFilePersistenceManager.class)
       </annotation>
       <annotation expr="!class(@org.jboss.annotation.ejb.cache.simple.CacheConfig) AND !class(@org.jboss.annotation.ejb.Clustered)">
-         @org.jboss.annotation.ejb.cache.simple.CacheConfig (maxSize=100000, idleTimeoutSeconds=300)
+         @org.jboss.annotation.ejb.cache.simple.CacheConfig (maxSize=100000, idleTimeoutSeconds=300, removalTimeoutSeconds=0)
       </annotation>
 
       <!-- Clustered cache configuration -->
@@ -201,7 +201,7 @@
          @org.jboss.annotation.ejb.cache.Cache (org.jboss.ejb3.cache.tree.StatefulTreeCache.class)
       </annotation>
       <annotation expr="!class(@org.jboss.annotation.ejb.cache.tree.CacheConfig) AND class(@org.jboss.annotation.ejb.Clustered)">
-         @org.jboss.annotation.ejb.cache.tree.CacheConfig (name="jboss.cache:service=EJB3SFSBClusteredCache", maxSize=100000, idleTimeoutSeconds=300)
+         @org.jboss.annotation.ejb.cache.tree.CacheConfig (name="jboss.cache:service=EJB3SFSBClusteredCache", maxSize=100000, idleTimeoutSeconds=300, removalTimeoutSeconds=0)
       </annotation>
    </domain>
 
@@ -253,7 +253,7 @@
          @org.jboss.annotation.ejb.cache.simple.PersistenceManager (org.jboss.ejb3.cache.simple.StatefulSessionFilePersistenceManager.class)
       </annotation>
       <annotation expr="!class(@org.jboss.annotation.ejb.cache.simple.CacheConfig) AND !class(@org.jboss.annotation.ejb.Clustered)">
-         @org.jboss.annotation.ejb.cache.simple.CacheConfig (maxSize=100000, idleTimeoutSeconds=300)
+         @org.jboss.annotation.ejb.cache.simple.CacheConfig (maxSize=100000, idleTimeoutSeconds=300, removalTimeoutSeconds=0)
       </annotation>
 
       <!-- Clustered cache configuration -->
@@ -261,7 +261,7 @@
          @org.jboss.annotation.ejb.cache.Cache (org.jboss.ejb3.cache.tree.StatefulTreeCache.class)
       </annotation>
       <annotation expr="!class(@org.jboss.annotation.ejb.cache.tree.CacheConfig) AND class(@org.jboss.annotation.ejb.Clustered)">
-         @org.jboss.annotation.ejb.cache.tree.CacheConfig (name="jboss.cache:service=EJB3SFSBClusteredCache", maxSize=100000, idleTimeoutSeconds=300)
+         @org.jboss.annotation.ejb.cache.tree.CacheConfig (name="jboss.cache:service=EJB3SFSBClusteredCache", maxSize=100000, idleTimeoutSeconds=300, removalTimeoutSeconds=0)
       </annotation>
    </domain>
 

Modified: trunk/ejb3/src/resources/test/stateful/META-INF/ejb-jar.xml
===================================================================
--- trunk/ejb3/src/resources/test/stateful/META-INF/ejb-jar.xml	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/resources/test/stateful/META-INF/ejb-jar.xml	2007-03-15 01:13:03 UTC (rev 61333)
@@ -35,5 +35,15 @@
          <session-type>Stateful</session-type>
          <transaction-type>Container</transaction-type>
       </session>
+      <session>
+         <ejb-name>StatefulTimeoutBean2</ejb-name>
+         <ejb-class>org.jboss.ejb3.test.stateful.StatefulTimeoutBean</ejb-class>
+         <session-type>Stateful</session-type>
+      </session>
+      <session>
+         <ejb-name>StatefulClusteredTimeoutBean2</ejb-name>
+         <ejb-class>org.jboss.ejb3.test.stateful.StatefulClusteredTimeoutBean</ejb-class>
+         <session-type>Stateful</session-type>
+      </session>
    </enterprise-beans>
 </ejb-jar>

Modified: trunk/ejb3/src/resources/test/stateful/META-INF/jboss.xml
===================================================================
--- trunk/ejb3/src/resources/test/stateful/META-INF/jboss.xml	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/resources/test/stateful/META-INF/jboss.xml	2007-03-15 01:13:03 UTC (rev 61333)
@@ -12,5 +12,20 @@
          <jndi-name>OverrideConcurrentStateful</jndi-name>
          <concurrent>false</concurrent>
       </session>
+      <session>
+         <ejb-name>StatefulTimeoutBean2</ejb-name>
+         <cache-config>
+            <idle-timeout-seconds>1</idle-timeout-seconds>
+            <remove-timeout-seconds>3</remove-timeout-seconds>
+         </cache-config>
+      </session>
+      <session>
+         <ejb-name>StatefulClusteredTimeoutBean2</ejb-name>
+         <cache-config>
+            <idle-timeout-seconds>1</idle-timeout-seconds>
+            <remove-timeout-seconds>3</remove-timeout-seconds>
+            <cache-name>jboss.cache:service=EJB3SFSBClusteredCache</cache-name>
+         </cache-config>
+      </session>
    </enterprise-beans>
 </jboss>

Added: trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulClusteredTimeoutBean.java
===================================================================
--- trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulClusteredTimeoutBean.java	                        (rev 0)
+++ trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulClusteredTimeoutBean.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ejb3.test.stateful;
+
+import javax.ejb.Remote;
+import javax.ejb.Remove;
+import javax.ejb.Stateful;
+
+import org.jboss.annotation.ejb.Clustered;
+import org.jboss.annotation.ejb.cache.tree.CacheConfig;
+import org.jboss.logging.Logger;
+
+/**
+ * @author <a href="mailto:bdecoste at jboss.com">William DeCoste</a>
+ */
+ at Stateful
+ at Remote(StatefulTimeout.class)
+ at CacheConfig(removalTimeoutSeconds = 1)
+ at Clustered
+public class StatefulClusteredTimeoutBean implements StatefulTimeout
+{
+   private static final Logger log = Logger.getLogger(StatefulClusteredTimeoutBean.class);
+   
+   public void test() 
+   {
+   }
+   
+   @Remove
+   public void remove()
+   {
+   }
+}

Added: trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeout.java
===================================================================
--- trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeout.java	                        (rev 0)
+++ trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeout.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -0,0 +1,35 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ejb3.test.stateful;
+
+
+
+/**
+ * @author <a href="mailto:bdecoste at jboss.com">William DeCoste</a>
+ */
+public interface StatefulTimeout
+{
+   void test();
+   
+   void remove();
+
+}

Added: trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeoutBean.java
===================================================================
--- trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeoutBean.java	                        (rev 0)
+++ trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/StatefulTimeoutBean.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.ejb3.test.stateful;
+
+import javax.ejb.Remote;
+import javax.ejb.Remove;
+import javax.ejb.Stateful;
+
+import org.jboss.annotation.ejb.cache.simple.CacheConfig;
+import org.jboss.logging.Logger;
+
+/**
+ * @author <a href="mailto:bdecoste at jboss.com">William DeCoste</a>
+ */
+ at Stateful
+ at Remote(StatefulTimeout.class)
+ at CacheConfig(removalTimeoutSeconds = 1)
+public class StatefulTimeoutBean implements StatefulTimeout
+{
+   private static final Logger log = Logger.getLogger(StatefulTimeoutBean.class);
+   
+   public void test() 
+   {
+   }
+   
+   @Remove
+   public void remove()
+   {
+   }
+}

Modified: trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/unit/RemoteUnitTestCase.java
===================================================================
--- trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/unit/RemoteUnitTestCase.java	2007-03-14 20:29:19 UTC (rev 61332)
+++ trunk/ejb3/src/test/org/jboss/ejb3/test/stateful/unit/RemoteUnitTestCase.java	2007-03-15 01:13:03 UTC (rev 61333)
@@ -22,6 +22,7 @@
 package org.jboss.ejb3.test.stateful.unit;
 
 import java.util.Map;
+import java.util.Random;
 
 import javax.ejb.NoSuchEJBException;
 import javax.management.MBeanServerConnection;
@@ -39,6 +40,7 @@
 import org.jboss.ejb3.test.stateful.Stateful;
 import org.jboss.ejb3.test.stateful.StatefulInvoker;
 import org.jboss.ejb3.test.stateful.StatefulLocal;
+import org.jboss.ejb3.test.stateful.StatefulTimeout;
 import org.jboss.ejb3.test.stateful.StatefulTx;
 import org.jboss.ejb3.test.stateful.ProxyFactoryInterface;
 import org.jboss.ejb3.test.stateful.RemoteBindingInterceptor;
@@ -115,6 +117,60 @@
       }
    }
    
+   private class ConcurrentStatefulTimeoutClient extends Thread
+   {
+      StatefulTimeout sfsb;
+      public Exception ex;
+      private int id;
+      private int wait;
+      public Exception e;
+      public boolean removed = false;
+      
+      public ConcurrentStatefulTimeoutClient(int id, int wait)
+      {
+         try
+         {
+            this.id = id;
+            this.wait = wait;
+            sfsb = (StatefulTimeout)getInitialContext().lookup("StatefulClusteredTimeoutBean/remote");
+         }
+         catch (Exception e)
+         {
+         }
+      }
+      
+      public void run()
+      {
+         Random random = new Random(id);
+         
+         while (!removed)
+         {
+            try
+            {
+               sfsb.test();
+               int millis = random.nextInt(wait);
+               if (millis <= wait/10)
+               {
+                  sfsb.remove();
+                  removed = true;
+                  System.out.println("Bean has been removed " + id);
+               }
+               else
+                  Thread.sleep(millis);
+            }
+            catch (javax.ejb.NoSuchEJBException e)
+            {
+               System.out.println("Bean has timed out " + id);
+               removed = true;
+            }
+            catch (Exception e)
+            {
+               this.e = e;
+            }
+         }
+      }
+   }
+   
    public void testSmallCache() throws Exception
    {
       ConcurrentInvocation[] threads = new ConcurrentInvocation[5];
@@ -375,6 +431,95 @@
       long maxConnectionsInUseCount = (Long)server.getAttribute(objectName, "MaxConnectionsInUseCount");
       System.out.println("maxConnectionsInUseCount \n" + maxConnectionsInUseCount); 
    }
+   
+   public void testTimeoutRemoval() throws Exception
+   {
+      StatefulTimeout sfsb = (StatefulTimeout)getInitialContext().lookup("StatefulTimeoutBean/remote");
+      sfsb.test();
+      Thread.sleep(5 * 1000);
+      
+      try
+      {
+         sfsb.test();
+         fail("SFSB should have been removed via timeout");
+      } catch (javax.ejb.NoSuchEJBException e)
+      {
+      }
+      
+      sfsb = (StatefulTimeout)getInitialContext().lookup("StatefulTimeoutBean2/remote");
+      sfsb.test();
+      Thread.sleep(10 * 1000);
+      
+      try
+      {
+         sfsb.test();
+         fail("SFSB should have been removed via timeout");
+      } catch (javax.ejb.NoSuchEJBException e)
+      {
+      }
+   }
+   
+   public void testClusteredTimeoutRemoval() throws Exception
+   {
+      StatefulTimeout sfsb = (StatefulTimeout)getInitialContext().lookup("StatefulClusteredTimeoutBean/remote");
+      sfsb.test();
+      Thread.sleep(5 * 1000);
+      
+      try
+      {
+         sfsb.test();
+         fail("SFSB should have been removed via timeout");
+      } catch (javax.ejb.NoSuchEJBException e)
+      {
+      }
+      
+      sfsb = (StatefulTimeout)getInitialContext().lookup("StatefulClusteredTimeoutBean2/remote");
+      sfsb.test();
+      Thread.sleep(10 * 1000);
+      
+      try
+      {
+         sfsb.test();
+         fail("SFSB should have been removed via timeout");
+      } catch (javax.ejb.NoSuchEJBException e)
+      {
+      }
+   }
+   
+   public void testConcurrentClusteredTimeoutRemoval() throws Exception
+   {
+      int numThreads = 100;
+      ConcurrentStatefulTimeoutClient[] clients = new ConcurrentStatefulTimeoutClient[numThreads];
+      for (int i = 0 ; i < numThreads ; ++i)
+      {
+         clients[i] = new ConcurrentStatefulTimeoutClient(i, 3000);
+         clients[i].start();
+      }
+      
+      Thread.sleep(500);
+      ObjectName objectName = new ObjectName("jboss.j2ee:jar=stateful-test.jar,name=StatefulClusteredTimeoutBean,service=EJB3");
+      MBeanServerConnection server = getServer();
+      int size = (Integer)server.getAttribute(objectName, "TotalSize");
+      assertTrue(size > 0);
+      
+      boolean allRemoved = false;
+      while (!allRemoved)
+      {
+         int i = 0;
+         while (i < numThreads && clients[i].removed)
+            ++i;
+         
+         System.out.println("----- removed " + i);
+         
+         if (i == numThreads)
+            allRemoved = true;
+         
+         Thread.sleep(5000);
+      }
+      
+      size = (Integer)server.getAttribute(objectName, "TotalSize");
+      assertEquals(0, size);
+   }
 
    public void testPassivation() throws Exception
    {




More information about the jboss-cvs-commits mailing list