[jboss-cvs] JBossAS SVN: r75738 - in trunk: testsuite/imports/sections and 9 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Sun Jul 13 09:33:34 EDT 2008


Author: bstansberry at jboss.com
Date: 2008-07-13 09:33:32 -0400 (Sun, 13 Jul 2008)
New Revision: 75738

Added:
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/AttributeBasedMaxUnreplicatedIntervalTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/FieldBasedMaxUnreplicatedIntervalTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionBasedMaxUnreplicatedIntervalTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionTimestampTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsSystemPropertySupport.java
   trunk/testsuite/src/resources/cluster/http/http-sr/
   trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/
   trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/jboss-web.xml
   trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/web.xml
Removed:
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SimpleTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsConfigSupport.java
   trunk/testsuite/src/resources/cluster/http/web.xml
Modified:
   trunk/testsuite/imports/config/tests-clustering.xml
   trunk/testsuite/imports/sections/cluster.xml
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionCountUnitTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionExpirationUnitTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionEventTestCase.java
   trunk/testsuite/src/main/org/jboss/test/cluster/testutil/CacheConfigTestSetup.java
   trunk/testsuite/src/main/org/jboss/test/cluster/testutil/SessionTestUtil.java
   trunk/testsuite/src/resources/cluster/http/testsessionreplication.jsp
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/deployers/ClusteringDefaultsDeployer.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java
   trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
   trunk/tomcat/src/resources/war-deployers-beans.xml
Log:
[JBAS-5751] Make max unreplicated time for clustered session configurable

Modified: trunk/testsuite/imports/config/tests-clustering.xml
===================================================================
--- trunk/testsuite/imports/config/tests-clustering.xml	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/imports/config/tests-clustering.xml	2008-07-13 13:33:32 UTC (rev 75738)
@@ -468,6 +468,7 @@
     <antcall target="tests-clustering-unit">
       <param name="cluster.includes.refid" value="one.test.includes"/>
       <param name="jboss-junit-configuration" value="Default-${jboss-junit-configuration}"/>
+      <param name="jbosstest.cluster.web.cache.config" value="standard-session-cache"/>
       <param name="jbosstest.cluster.node0.config" value="cluster-${jboss-junit-configuration}-0"/>
       <param name="jbosstest.cluster.node1.config" value="cluster-${jboss-junit-configuration}-1"/>
     </antcall>

Modified: trunk/testsuite/imports/sections/cluster.xml
===================================================================
--- trunk/testsuite/imports/sections/cluster.xml	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/imports/sections/cluster.xml	2008-07-13 13:33:32 UTC (rev 75738)
@@ -131,7 +131,10 @@
    	
       <!-- build httpsessionreplication.jar -->
       <war warfile="${build.lib}/http-sr.war"
-         webxml="${build.resources}/cluster/http/web.xml">
+         webxml="${build.resources}/cluster/http/http-sr/WEB-INF/web.xml">
+         <webinf dir="${build.resources}/cluster/http/http-sr/WEB-INF">
+            <include name="jboss-web.xml"/>
+         </webinf>
          <fileset dir="${build.resources}/cluster/http">
             <include name="*.jsp"/>
          </fileset>

Added: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/AttributeBasedMaxUnreplicatedIntervalTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/AttributeBasedMaxUnreplicatedIntervalTestCase.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/AttributeBasedMaxUnreplicatedIntervalTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,143 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.test.cluster.defaultcfg.simpleweb.test;
+
+import junit.framework.Test;
+
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.test.cluster.testutil.CacheConfigTestSetup;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.test.cluster.web.mocks.BasicRequestHandler;
+import org.jboss.test.cluster.web.mocks.SetAttributesRequestHandler;
+import org.jboss.web.tomcat.service.session.JBossCacheManager;
+
+/**
+ * Tests of handling of ClusteredSession.maxUnreplicatedInterval. This version
+ * is run with ATTRIBUTE granularity.
+ * 
+ * @author Brian Stansberry
+ *
+ */
+public class AttributeBasedMaxUnreplicatedIntervalTestCase 
+   extends SessionBasedMaxUnreplicatedIntervalTestCase
+{      
+   public AttributeBasedMaxUnreplicatedIntervalTestCase(String name)
+   {
+      super(name);
+   }
+   
+   public static Test suite() throws Exception
+   {
+      return CacheConfigTestSetup.getTestSetup(AttributeBasedMaxUnreplicatedIntervalTestCase.class, pojoCaches, false, null, !useBuddyRepl, false);
+   }
+   
+   protected ReplicationGranularity getReplicationGranularity()
+   {
+      return ReplicationGranularity.ATTRIBUTE;
+   }  
+   
+   /**
+    * A test of the "grace period" that maxUnreplicatedInterval adds to the
+    * removal of overaged unloaded sessions in remote caches. Confirms that a
+    * session still in the "grace period" doesn't have its cache structure
+    * removed.
+    * 
+    * @throws Exception
+    */
+   public void testMaxIntervalPreventsLossOfRemoteState() throws Exception
+   {
+      log.info("++++ Starting testMaxIntervalPreventsLossOfRemoteState ++++");
+      
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 3 secs and a maxUnreplicated of 1
+      JBossCacheManager[] mgrs = getCacheManagers(warname, 3, 1);
+      JBossCacheManager jbcm0 = mgrs[0];
+      JBossCacheManager jbcm1 = mgrs[1];
+      
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler, null);
+      
+      validateNewSession(setHandler);
+      
+      Thread.sleep(250);
+      
+      // Now make a request that will not trigger replication but keeps the jbcm0 session alive
+      BasicRequestHandler getHandler = new BasicRequestHandler(immutables.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm0, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(immutables, getHandler);
+      
+      // Sleep long enough that the session will be expired on other server
+      // if it doesn't have a maxUnreplicatedInterval grace period
+      Thread.sleep(2800);
+      
+      // jbcm1 considers the session unmodified for > 3 sec maxInactiveInterval.
+      // Try to drive the session out of the jbcm1 cache      
+      jbcm1.backgroundProcess();
+      
+      // Replicate just one attribute; see if the other is still in jbcm1
+      SetAttributesRequestHandler modifyHandler = new SetAttributesRequestHandler(mutables, false);
+      SessionTestUtil.invokeRequest(jbcm0, modifyHandler, setHandler.getSessionId());
+      
+      // Fail over and confirm all is well. If the session was removed,
+      // the last replication of just one attribute won't restore all
+      // attributes and we'll have a failure
+      getHandler = new BasicRequestHandler(allAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm1, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(allAttributes, getHandler);
+   } 
+   
+   public void testDisabledMaxIntervalReplicatesOnDirtyAttribute() throws Exception
+   {
+      log.info("++++ Starting testDisabledMaxIntervalReplicatesOnDirtyAttribute ++++");
+      
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 2 secs and a maxUnreplicated of -1
+      JBossCacheManager[] mgrs = getCacheManagers(warname, 2, -1);
+      JBossCacheManager jbcm0 = mgrs[0];
+      JBossCacheManager jbcm1 = mgrs[1];
+      
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler, null);
+      
+      validateNewSession(setHandler);
+      
+      Thread.sleep(250);
+      
+      SetAttributesRequestHandler modifyHandler = new SetAttributesRequestHandler(mutables, false);
+      SessionTestUtil.invokeRequest(jbcm0, modifyHandler, setHandler.getSessionId());
+      
+      Thread.sleep(1760);
+      
+      // Fail over and confirm all is well
+      BasicRequestHandler getHandler = new BasicRequestHandler(allAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm1, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(allAttributes, getHandler);
+      
+   }
+
+}

Added: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/FieldBasedMaxUnreplicatedIntervalTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/FieldBasedMaxUnreplicatedIntervalTestCase.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/FieldBasedMaxUnreplicatedIntervalTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,59 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.test.cluster.defaultcfg.simpleweb.test;
+
+import junit.framework.Test;
+
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.test.cluster.testutil.CacheConfigTestSetup;
+
+/**
+ * Tests of handling of ClusteredSession.maxUnreplicatedInterval. This version
+ * is run with FIELD granularity.
+ * 
+ * @author Brian Stansberry
+ */
+public class FieldBasedMaxUnreplicatedIntervalTestCase 
+   extends AttributeBasedMaxUnreplicatedIntervalTestCase
+{      
+   /**
+    * Create a new MaxUnreplicatedIntervalTestCase.
+    * 
+    * @param name
+    */
+   public FieldBasedMaxUnreplicatedIntervalTestCase(String name)
+   {
+      super(name);
+   }
+   
+   public static Test suite() throws Exception
+   {
+      return CacheConfigTestSetup.getTestSetup(FieldBasedMaxUnreplicatedIntervalTestCase.class, pojoCaches, false, null, !useBuddyRepl, true);
+   }
+   
+   protected ReplicationGranularity getReplicationGranularity()
+   {
+      return ReplicationGranularity.FIELD;
+   }   
+
+}

Added: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionBasedMaxUnreplicatedIntervalTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionBasedMaxUnreplicatedIntervalTestCase.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionBasedMaxUnreplicatedIntervalTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,301 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.test.cluster.defaultcfg.simpleweb.test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.pojo.PojoCache;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.cluster.web.mocks.BasicRequestHandler;
+import org.jboss.test.cluster.testutil.CacheConfigTestSetup;
+import org.jboss.test.cluster.web.mocks.MutableObject;
+import org.jboss.test.cluster.web.mocks.SetAttributesRequestHandler;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.web.tomcat.service.session.JBossCacheManager;
+import org.jboss.web.tomcat.service.session.JBossCacheService;
+
+/**
+ * Tests of handling of ClusteredSession.maxUnreplicatedInterval.  This base
+ * test is run with SESSION granularity.
+ * 
+ * @author Brian Stansberry
+ */
+public class SessionBasedMaxUnreplicatedIntervalTestCase extends JBossTestCase
+{
+   protected static PojoCache[] pojoCaches = new PojoCache[2];
+
+   protected static long testId = System.currentTimeMillis();
+   
+   protected static boolean useBuddyRepl = Boolean.valueOf(System.getProperty("jbosstest.cluster.web.cache.br")).booleanValue();
+   
+   protected Logger log = Logger.getLogger(getClass());   
+   
+   protected Set<JBossCacheManager> managers = new HashSet<JBossCacheManager>();
+   
+   protected Map<String, Object> allAttributes;
+   protected Map<String, Object> immutables;
+   protected Map<String, Object> mutables;
+   
+   public SessionBasedMaxUnreplicatedIntervalTestCase(String name)
+   {
+      super(name);
+   }
+   
+   public static Test suite() throws Exception
+   {
+      return CacheConfigTestSetup.getTestSetup(SessionBasedMaxUnreplicatedIntervalTestCase.class, pojoCaches, false, null, !useBuddyRepl, false);
+   }
+
+   
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+      
+      allAttributes = new HashMap<String, Object>();
+      immutables = new HashMap<String, Object>();
+      mutables = new HashMap<String, Object>();
+      
+      allAttributes.put("IMMUTABLE", "IMMUTABLE");
+      immutables.put("IMMUTABLE", "IMMUTABLE");
+      
+      MutableObject mo = new MutableObject("MUTABLE");
+      allAttributes.put("MUTABLE", mo);
+      mutables.put("MUTABLE", mo);
+      
+      allAttributes = Collections.unmodifiableMap(allAttributes);
+      immutables = Collections.unmodifiableMap(immutables);
+      mutables = Collections.unmodifiableMap(mutables);
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      super.tearDown();
+      
+      for (JBossCacheManager manager : managers)      
+         manager.stop();
+      
+      managers.clear();
+   }
+   
+   protected ReplicationGranularity getReplicationGranularity()
+   {
+      return ReplicationGranularity.SESSION;
+   }
+   
+   protected ReplicationTrigger getReplicationTrigger()
+   {
+      return ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET;
+   }
+   
+   public void testBasicMaxIntervalPreventsExpiration() throws Exception
+   {
+      log.info("++++ Starting testBasicMaxIntervalPreventsExpiration ++++");
+      
+      maxIntervalPreventsExpirationTest(false);
+   }
+   
+   public void testZeroMaxIntervalPreventsExpiration() throws Exception
+   {
+      log.info("++++ Starting testZeroMaxIntervalPreventsExpiration ++++");
+      
+      maxIntervalPreventsExpirationTest(false);
+   }
+   
+   private void maxIntervalPreventsExpirationTest(boolean testZero) throws Exception
+   {
+      String warname = String.valueOf(++testId);
+      
+      int maxUnrep = testZero ? 0 : 1;
+      
+      // A war with a maxInactive of 3 secs and a maxUnreplicated of 0 or 1
+      JBossCacheManager[] mgrs = getCacheManagers(warname, 3, maxUnrep);
+      JBossCacheManager jbcm0 = mgrs[0];
+      JBossCacheManager jbcm1 = mgrs[1];
+      
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler, null);
+      
+      validateNewSession(setHandler);
+      
+      Thread.sleep(1050);
+      
+      // Now make a request that will not trigger replication unless the interval is exceeded
+      BasicRequestHandler getHandler = new BasicRequestHandler(immutables.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm0, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(immutables, getHandler);
+      
+      // Sleep long enough that the session will be expired on other server
+      // if previous request didn't keep it alive
+      Thread.sleep(2000);
+      
+      // Fail over and confirm all is well
+      getHandler = new BasicRequestHandler(allAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm1, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(allAttributes, getHandler);
+   }
+   
+   public void testMaxIntervalPreventsReplication() throws Exception
+   {
+      log.info("++++ Starting testMaxIntervalPreventsReplication ++++");
+      
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 3 secs and a maxUnreplicated of 1
+      JBossCacheManager[] mgrs = getCacheManagers(warname, 3, 1);
+      JBossCacheManager jbcm0 = mgrs[0];
+      JBossCacheManager jbcm1 = mgrs[1];
+      
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler, null);
+      
+      // Sleep less than the maxUnreplicated time so next request shouldn't trigger timestamp repl
+      Thread.sleep(500);
+      
+      // Now make a request that will not trigger replication unless the interval is exceeded
+      BasicRequestHandler getHandler = new BasicRequestHandler(immutables.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm0, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(immutables, getHandler);
+      
+      // Sleep long enough that the session will be expired on other server
+      // if previous request didn't keep it alive
+      Thread.sleep(2600);
+      
+      // Fail over and confirm the session was expired
+      getHandler = new BasicRequestHandler(allAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm1, getHandler, setHandler.getSessionId());
+      
+      validateNewSession(getHandler);
+   }
+   
+   /**
+    * Confirms that the "grace period" that maxUnreplicatedInterval adds to the
+    * removal of overaged unloaded sessions in remote caches delays their
+    * removal.
+    * 
+    * @throws Exception
+    */
+   public void testRemoteExpirationGracePeriod() throws Exception
+   {
+      log.info("++++ Starting testRemoteExpirationGracePeriod ++++");
+      
+      String warname = String.valueOf(++testId);
+      
+      JBossCacheManager[] mgrs = getCacheManagers(warname, 3, 2);
+      JBossCacheManager jbcm0 = mgrs[0];
+      JBossCacheManager jbcm1 = mgrs[1];
+      
+      SetAttributesRequestHandler setHandler1 = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler1, null);
+      
+      Fqn session1Fqn = Fqn.fromString("/JSESSION/localhost/" + warname + "/" + setHandler1.getSessionId());
+      
+      SetAttributesRequestHandler setHandler2 = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(jbcm0, setHandler2, null);
+      
+      Fqn session2Fqn = Fqn.fromString("/JSESSION/localhost/" + warname + "/" + setHandler2.getSessionId());
+      
+      // Overage the sessions
+      Thread.sleep(3010);
+      // Try to force out the overaged sessions
+      jbcm1.backgroundProcess();
+      // Confirm they are still there
+      assertNotNull(pojoCaches[1].getCache().get(session1Fqn, JBossCacheService.VERSION_KEY));
+      assertNotNull(pojoCaches[1].getCache().get(session2Fqn, JBossCacheService.VERSION_KEY));
+      
+      // Access one to prove it gets expired once the manager can see its real timestamp
+      BasicRequestHandler getHandler = new BasicRequestHandler(allAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(jbcm1, getHandler, setHandler1.getSessionId());      
+      validateNewSession(getHandler);
+      
+      // Sleep past the grace period
+      Thread.sleep(2010);
+      // The get restored a new fresh session with the first id, but the 2nd 
+      // one is still there and overaged. Try to force it out
+      jbcm1.backgroundProcess();
+      assertNull(pojoCaches[1].getCache().get(session2Fqn, JBossCacheService.VERSION_KEY));
+   }
+   
+   protected JBossCacheManager[] getCacheManagers(String warname, int maxInactive, int maxUnreplicated)
+      throws Exception
+   {
+      JBossCacheManager jbcm0 = SessionTestUtil.createManager(warname, maxInactive, pojoCaches[0], null);
+      JBossWebMetaData metadata = SessionTestUtil.createWebMetaData(getReplicationGranularity(), getReplicationTrigger(), true, maxUnreplicated);
+      jbcm0.init(warname, metadata);
+      this.managers.add(jbcm0);
+      jbcm0.start();
+      
+      JBossCacheManager jbcm1 = SessionTestUtil.createManager(warname, maxInactive, pojoCaches[1], null);
+      metadata = SessionTestUtil.createWebMetaData(getReplicationGranularity(), getReplicationTrigger(), true, maxUnreplicated);
+      jbcm1.init(warname, metadata);
+      this.managers.add(jbcm1);
+      jbcm1.start();
+      
+      return new JBossCacheManager[]{jbcm0, jbcm1};
+   }
+   
+   protected void validateExpectedAttributes(Map<String, Object> expected, BasicRequestHandler handler)
+   {
+      assertFalse(handler.isNewSession());
+      
+      if (handler.isCheckAttributeNames())
+      {
+         assertEquals(expected.size(), handler.getAttributeNames().size());
+      }
+      Map<String, Object> checked = handler.getCheckedAttributes();
+      assertEquals(expected.size(), checked.size());
+      for (Map.Entry<String, Object> entry : checked.entrySet())
+         assertEquals(entry.getKey(), expected.get(entry.getKey()), entry.getValue());
+      
+   }
+   
+   protected void validateNewSession(BasicRequestHandler handler)
+   {
+      assertTrue(handler.isNewSession());
+      assertEquals(handler.getCreationTime(), handler.getLastAccessedTime());
+      if (handler.isCheckAttributeNames())
+      {
+         assertEquals(0, handler.getAttributeNames().size());
+      }
+      Map<String, Object> checked = handler.getCheckedAttributes();
+      for (Map.Entry<String, Object> entry : checked.entrySet())
+         assertNull(entry.getKey(), entry.getValue());
+   }
+   
+
+}

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionCountUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionCountUnitTestCase.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionCountUnitTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -35,7 +35,7 @@
 import org.jboss.cache.pojo.PojoCache;
 import org.jboss.logging.Logger;
 import org.jboss.metadata.web.jboss.JBossWebMetaData;
-import org.jboss.test.cluster.testutil.JGroupsConfigSupport;
+import org.jboss.test.cluster.testutil.JGroupsSystemPropertySupport;
 import org.jboss.test.cluster.testutil.SessionTestUtil;
 import org.jboss.web.tomcat.service.session.JBossCacheManager;
 
@@ -51,7 +51,7 @@
    
    private static long testCount = System.currentTimeMillis();
    
-   private JGroupsConfigSupport jgroupsSupport;
+   private JGroupsSystemPropertySupport jgroupsSupport;
    private Set<PojoCache> caches = new HashSet<PojoCache>();
    private String tempDir;
    
@@ -72,8 +72,8 @@
       super.setUp();
       
       // Set system properties to properly bind JGroups channels
-      jgroupsSupport = new JGroupsConfigSupport();
-      jgroupsSupport.setUp();
+      jgroupsSupport = new JGroupsSystemPropertySupport();
+      jgroupsSupport.setUpProperties();
       
       File tmpDir = new File(System.getProperty("java.io.tmpdir"));
       File root = new File(tmpDir, getClass().getSimpleName());
@@ -83,46 +83,55 @@
    @Override
    protected void tearDown() throws Exception
    {
-      super.tearDown();
-      
-      // Restore any system properties we set in setUp
-      jgroupsSupport.tearDown();
-      
-      for (PojoCache cache : caches)
-      { 
-         // Try to clean up so we avoid loading sessions 
-         // from storage in later tests
-         try
+      try
+      {
+         super.tearDown();
+      }
+      finally
+      {      
+         // Restore any system properties we set in setUp
+         if (jgroupsSupport != null)
          {
-            log.info("Removing /JSESSION from " + cache.getCache().getLocalAddress());
-            cache.getCache().removeNode(Fqn.fromString("/JSESSION"));
+            jgroupsSupport.restoreProperties();
          }
-         catch (Exception e)
-         {
-            log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
+      
+         for (PojoCache cache : caches)
+         { 
+            // Try to clean up so we avoid loading sessions 
+            // from storage in later tests
+            try
+            {
+               log.info("Removing /JSESSION from " + cache.getCache().getLocalAddress());
+               cache.getCache().removeNode(Fqn.fromString("/JSESSION"));
+            }
+            catch (Exception e)
+            {
+               log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
+            }
+            
+            try
+            {
+               cache.stop();
+               cache.destroy();
+            }
+            catch (Exception e)
+            {
+               log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
+            }
+            
          }
          
-         try
+         caches.clear();
+         
+         if (tempDir != null)
          {
-            cache.stop();
-            cache.destroy();
+            File dir = new File(tempDir);
+            if (dir.exists())
+               dir.delete();
+            if (dir.exists())
+               dir.deleteOnExit();
          }
-         catch (Exception e)
-         {
-            log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
-         }
       }
-      
-      caches.clear();
-      
-      if (tempDir != null)
-      {
-         File dir = new File(tempDir);
-         if (dir.exists())
-            dir.delete();
-         if (dir.exists())
-            dir.deleteOnExit();
-      }
    }
 
    public void testStandaloneMaxSessions() throws Exception

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionExpirationUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionExpirationUnitTestCase.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/SessionExpirationUnitTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -25,17 +25,17 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import junit.framework.TestCase;
+
 import org.apache.catalina.Session;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.pojo.PojoCache;
 import org.jboss.logging.Logger;
 import org.jboss.metadata.web.jboss.JBossWebMetaData;
-import org.jboss.test.cluster.testutil.JGroupsConfigSupport;
+import org.jboss.test.cluster.testutil.JGroupsSystemPropertySupport;
 import org.jboss.test.cluster.testutil.SessionTestUtil;
 import org.jboss.web.tomcat.service.session.JBossCacheManager;
 
-import junit.framework.TestCase;
-
 /**
  * Unit tests of session expiration
  * 
@@ -50,7 +50,7 @@
    
    private static long testCount = System.currentTimeMillis();
    
-   private JGroupsConfigSupport jgroupsSupport;
+   private JGroupsSystemPropertySupport jgroupsSupport;
    private Set<PojoCache> caches = new HashSet<PojoCache>();
 
    /**
@@ -68,43 +68,51 @@
       super.setUp();
       
       // Set system properties to properly bind JGroups channels
-      jgroupsSupport = new JGroupsConfigSupport();
-      jgroupsSupport.setUp();
+      jgroupsSupport = new JGroupsSystemPropertySupport();
+      jgroupsSupport.setUpProperties();
    }
 
    protected void tearDown() throws Exception
    {
-      super.tearDown();
-      
-      // Restore any system properties we set in setUp
-      jgroupsSupport.tearDown();
-      
-      for (PojoCache cache : caches)
-      { 
-         // Try to clean up so we avoid loading sessions 
-         // from storage in later tests
-         try
+      try
+      {
+         super.tearDown();
+      }
+      finally
+      {
+         // Restore any system properties we set in setUp
+         if (jgroupsSupport != null)
          {
-            log.info("Removing /JSESSION from " + cache.getCache().getLocalAddress());
-            cache.getCache().removeNode(Fqn.fromString("/JSESSION"));
+            jgroupsSupport.restoreProperties();
          }
-         catch (Exception e)
-         {
-            log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
+         
+         for (PojoCache cache : caches)
+         { 
+            // Try to clean up so we avoid loading sessions 
+            // from storage in later tests
+            try
+            {
+               log.info("Removing /JSESSION from " + cache.getCache().getLocalAddress());
+               cache.getCache().removeNode(Fqn.fromString("/JSESSION"));
+            }
+            catch (Exception e)
+            {
+               log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
+            }
+            
+            try
+            {
+               cache.stop();
+               cache.destroy();
+            }
+            catch (Exception e)
+            {
+               log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
+            }
          }
          
-         try
-         {
-            cache.stop();
-            cache.destroy();
-         }
-         catch (Exception e)
-         {
-            log.error("Cache " + cache.getCache().getLocalAddress() + ": " + e.getMessage(), e);
-         }
+         caches.clear();
       }
-      
-      caches.clear();
    }
 
    /**

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionEventTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionEventTestCase.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionEventTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -64,7 +64,7 @@
 
       // Set the session attribute first
       attr = makeGet(client, baseURL0_ +setURLName);
-System.out.println("*** Response is " +attr);
+      log.info("*** Response is " +attr);
 
       assertNotNull("Http session get", attr);
       boolean isOK = false;

Copied: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionTimestampTestCase.java (from rev 75719, trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SimpleTestCase.java)
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionTimestampTestCase.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SessionTimestampTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,179 @@
+/*
+  * JBoss, Home of Professional Open Source
+  * Copyright 2005, JBoss Inc., and individual contributors as indicated
+  * by the @authors tag. See the copyright.txt 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.test.cluster.defaultcfg.web.test;
+
+import java.io.IOException;
+
+import junit.framework.Test;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.test.cluster.testutil.WebTestBase;
+import org.jboss.test.cluster.web.JBossClusteredWebTestCase;
+
+/**
+ * Tests handling of the session timestamp.
+ *
+ * @author Ben Wang
+ * @author Brian Stansberry
+ * @version $Revision: 1.0
+ */
+public class SessionTimestampTestCase
+      extends WebTestBase
+{
+
+   public SessionTimestampTestCase(String name)
+   {
+      super(name);
+
+   }
+
+   public static Test suite() throws Exception
+   {
+      return JBossClusteredWebTestCase.getDeploySetup(SessionTimestampTestCase.class,
+                                                      "http-sr.war");
+   }
+   
+   /**
+    * Tests that sessions time out properly and that activity
+    * on one cluster node prevents timeout on another.
+    * 
+    * The session is configured by testsessionreplication.jsp to expire
+    * after 10 seconds. It is configured by jboss-web.xml with a 
+    * maxUnreplicatedInterval of 8 secs.
+    */
+   public void testSessionTimeout()
+      throws Exception
+   {
+      getLog().debug("Enter testSessionTimeout");
+
+      String setURLName = "/http-sr/testsessionreplication.jsp";
+      String getURLName = "/http-sr/getattribute.jsp";
+
+      getLog().debug(setURLName + ":::::::" + getURLName);
+
+      // Create first session on server0
+      HttpClient clientA = new HttpClient();
+      makeGet(clientA, baseURL0_ +setURLName);
+
+      sleepThread(3000);
+      
+      // Update the first session to ensure timestamp replication occurs
+      makeGetWithState(clientA, baseURL0_ +setURLName);
+      // Get the Attribute set by testsessionreplication.jsp
+      String attrA0 = makeGetWithState(clientA, baseURL0_ +getURLName);
+      assertNotNull("Http session get", attrA0);
+
+      sleepThread(1100);
+      
+      // Create a 2nd session
+      HttpClient clientB = new HttpClient();
+      makeGet(clientB, baseURL0_ +setURLName);
+      // Get the Attribute set by testsessionreplication.jsp
+      String attrB0 = makeGetWithState(clientB, baseURL0_ +getURLName);
+      assertNotNull("Http session get", attrB0);
+      
+      // Sleep 6 secs.  This plus the previous 1.1+3 secs is enough to expire
+      // first session on server1 if replication failed to keep it alive      
+      sleepThread(7000);
+      
+      // Switch to the other server and check if 1st session is alive
+      // This session has a create time > 8 secs ago, so this will trigger
+      // replication of the timestamp
+      SessionTestUtil.setCookieDomainToThisServer(clientA, servers_[1]);
+      String attrA1 = makeGetWithState(clientA, baseURL1_ +getURLName);
+      assertEquals("Http session replication attributes retrieved from both servers ", attrA0, attrA1);
+      
+      // Switch to the other server and check if 2nd session is alive
+      // This session has a create time < 8 secs ago, so this should not
+      // trigger replication of the timestamp      
+      SessionTestUtil.setCookieDomainToThisServer(clientB, servers_[1]);
+      String attrB1 = makeGetWithState(clientB, baseURL1_ +getURLName);
+      assertEquals("Http session replication attributes retrieved from both servers ", attrB0, attrB1);
+      
+      getLog().debug("Replication has kept the sessions alive");
+      
+      // sleep 2 more seconds so 1st session will expire on server0 if the
+      // get didn't replicate the timestamp
+      sleepThread(2000);  
+      
+      // Confirm first session is alive on node 0
+      SessionTestUtil.setCookieDomainToThisServer(clientA, servers_[0]);
+      attrA0 = makeGetWithState(clientA, baseURL0_ +getURLName);
+      assertTrue("Original session A is present", attrA1.equals(attrA0));  
+      
+      // sleep 1.1 more secs. Last activity for second session on server 0
+      // will have been 1.1 + 2 + 7 = 10.1 secs ago, so it should be expired
+      // on server 0
+      sleepThread(1100);
+      
+      // Confirm 2nd session is not alive on node 0
+      SessionTestUtil.setCookieDomainToThisServer(clientB, servers_[0]);
+      attrB0 = makeGetWithState(clientB, baseURL0_ +getURLName);
+      assertFalse("Original session B not alive", attrB1.equals(attrB0));
+      
+      getLog().debug("Exit testSessionTimeout");
+   }
+   
+   /**
+    * Tests that a request before maxUnreplicatedInterval has passed doesn't
+    * trigger replication.
+    */
+   public void testMaxUnreplicatedInterval() throws IOException
+   {
+      getLog().debug("Enter testMaxUnreplicatedInterval");
+
+      String setURLName = "/http-sr/testsessionreplication.jsp";
+      String getURLName = "/http-sr/getattribute.jsp";
+      String versionURLName = "/http-sr/version.jsp";
+
+      // Create an instance of HttpClient.
+      HttpClient client = new HttpClient();
+
+      // Set the session attribute first
+      makeGet(client, baseURL0_ +setURLName);
+      // Get the Attribute set by testsessionreplication.jsp
+      String attr = makeGetWithState(client, baseURL0_ +getURLName);
+      
+      // Sleep a bit, but less than the 16 sec maxUnreplicatedInterval
+      sleepThread(500);
+      
+      // Access the session without touching any attribute
+      String ver = makeGetWithState(client, baseURL0_ +versionURLName);
+      
+      // Sleep some more, long enough for the session replication to complete
+      // if the last request incorrectly caused replication 
+      sleepThread(2000);
+      
+      // Switch servers
+      SessionTestUtil.setCookieDomainToThisServer(client, servers_[1]);      
+      String ver1 = makeGetWithState(client, baseURL1_ +versionURLName);
+      
+      assertEquals("Session version count unchanged", ver, ver1);
+      
+      // Get the Attribute set by testsessionreplication.jsp
+      String attr1 = makeGetWithState(client, baseURL1_ +getURLName);
+      
+      assertEquals("Session still present", attr, attr1);
+   }
+
+}

Deleted: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SimpleTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SimpleTestCase.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/SimpleTestCase.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -1,245 +0,0 @@
-/*
-  * JBoss, Home of Professional Open Source
-  * Copyright 2005, JBoss Inc., and individual contributors as indicated
-  * by the @authors tag. See the copyright.txt 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.test.cluster.defaultcfg.web.test;
-
-import java.io.IOException;
-
-import javax.management.MBeanServerConnection;
-
-import junit.framework.Test;
-
-import org.apache.commons.httpclient.HttpClient;
-import org.jboss.test.cluster.testutil.SessionTestUtil;
-import org.jboss.test.cluster.testutil.WebTestBase;
-import org.jboss.test.cluster.web.JBossClusteredWebTestCase;
-
-/**
- * Simple clustering test case of get/set.
- *
- * @author Ben Wang
- * @version $Revision: 1.0
- */
-public class SimpleTestCase
-      extends WebTestBase
-{
-
-   public SimpleTestCase(String name)
-   {
-      super(name);
-
-   }
-
-   public static Test suite() throws Exception
-   {
-      return JBossClusteredWebTestCase.getDeploySetup(SimpleTestCase.class,
-                                                      "http-sr.war");
-   }
-
-   /**
-    * Main method that deals with the Http Session Replication Test
-    *
-    * @throws Exception
-    */
-   public void testHttpSessionReplication()
-         throws Exception
-   {
-      String attr = "";
-      getLog().debug("Enter testHttpSessionReplication");
-
-      String setURLName = "/http-sr/testsessionreplication.jsp";
-      String getURLName = "/http-sr/getattribute.jsp";
-
-      getLog().debug(setURLName + ":::::::" + getURLName);
-
-      // Create an instance of HttpClient.
-      HttpClient client = new HttpClient();
-
-      // Set the session attribute first
-      makeGet(client, baseURL0_ +setURLName);
-
-      // Get the Attribute set by testsessionreplication.jsp
-      attr = makeGetWithState(client, baseURL0_ +getURLName);
-
-      sleepThread(DEFAULT_SLEEP);
-
-      // Let's switch to server 2 to retrieve the session attribute.
-      SessionTestUtil.setCookieDomainToThisServer(client, servers_[1]);
-      String attr2 = makeGet(client, baseURL1_ +getURLName);
-
-      // Check the result
-      assertEquals("Http session replication attribtues retrieved from both servers ", attr, attr2);
-
-      getLog().debug("Http Session Replication has happened");
-      getLog().debug("Exit testHttpSessionReplication");
-   }
-
-   /**
-    * Tests that sessions time out properly and that activity
-    * on one cluster node prevents timeout on another.
-    */
-   public void testSessionTimeout()
-      throws Exception
-   {
-      String attr  = "";
-      String attr2 = "";
-      getLog().debug("Enter testSessionTimeout");
-
-      String setURLName = "/http-sr/testsessionreplication.jsp";
-      String getURLName = "/http-sr/getattribute.jsp";
-
-      getLog().debug(setURLName + ":::::::" + getURLName);
-
-      // Create a session on server0
-      HttpClient client = new HttpClient();
-      makeGet(client, baseURL0_ +setURLName);
-
-      // Create a session on server 1.
-      HttpClient client1 = new HttpClient();
-      makeGet(client1, baseURL1_ +setURLName);
-      
-      // Find out the session id and use it to build an FQN
-      String sessionID = getSessionID(client1, servers_[1]);
-      // Strip off the jvmRoute, if there is one
-      sessionID = stripJvmRoute(sessionID);
-      String sessionFqn = "/JSESSION/localhost/http-sr/" + sessionID;
-
-      sleepThread(6000);
-      
-      // Set the server0 session to ensure replication occurs
-      attr = makeGetWithState(client, baseURL0_ +setURLName);
-      // Get the Attribute set by testsessionreplication.jsp
-      attr = makeGetWithState(client, baseURL0_ +getURLName);
-      assertNotNull("Http session get", attr);
-      
-      // Sleep 15 secs.  This plus the previous 6 secs is enough to expire
-      // session0 on server1 if replication failed to keep it alive
-      sleepThread(15000);
-      
-      // Switch to the other server and check if 1st session is alive
-      SessionTestUtil.setCookieDomainToThisServer(client, servers_[1]);
-      attr2 = makeGetWithState(client, baseURL1_ +getURLName);
-      
-      // Check the result
-      assertEquals("Http session replication attributes retrieved from both servers ", attr, attr2);
-      
-      getLog().debug("Replication has kept the session alive");
-      
-      // sleep 6 more seconds so session0 will expire on server0
-      sleepThread(6000);  
-      
-      // Confirm first session is expired on node 0
-      SessionTestUtil.setCookieDomainToThisServer(client, servers_[0]);
-      attr = makeGetWithState(client, baseURL0_ +getURLName);
-      assertFalse("Original session not present", attr2.equals(attr));
-      
-      // sleep 45 more seconds so session 1 will expire on server0.
-      // need a total of 70 secs -- 60 to expire and 10 to ensure the 
-      // bg thread runs. 20 secs to expire is not enough as the reduced
-      // life of this session is not available to the manager w/o 
-      // deserializing the session
-      sleepThread(45000);
-      
-      // Confirm 2nd session is gone from the distributed cache on node 0
-      MBeanServerConnection[] adaptors = getAdaptors();
-      assertNull("Session gone from distributed cache", 
-            SessionTestUtil.getSessionVersion(adaptors[0], sessionFqn));
-      assertNull("Session gone from distributed cache", 
-            SessionTestUtil.getBuddySessionVersion(adaptors[0], sessionFqn));
-      
-      getLog().debug("Exit testSessionTimeout");
-   }
-   
-   public void testMaxUnreplicatedInterval1()
-      throws Exception
-   {
-      getLog().debug("Enter testMaxUnreplicatedInterval");
-
-      String setURLName = "/http-sr/testsessionreplication.jsp";
-      String getURLName = "/http-sr/getattribute.jsp";
-      String accessURLName = "/http-sr/access.jsp";
-
-      // Create an instance of HttpClient.
-      HttpClient client = new HttpClient();
-
-      // Set the session attribute first
-      makeGet(client, baseURL0_ +setURLName);
-      // Get the Attribute set by testsessionreplication.jsp
-      String attr = makeGetWithState(client, baseURL0_ +getURLName);
-      
-      // Sleep 90% of the maxInactiveInterval
-      sleepThread(18000);
-      
-      // Access the session without touching any attribute
-      makeGet(client, baseURL0_ +accessURLName);
-      
-      // Sleep some more, long enough for the session to expire
-      // if access didn't cause replication and for the bg thread to run
-      sleepThread(17000);
-      
-      // Switch servers
-      SessionTestUtil.setCookieDomainToThisServer(client, servers_[1]);
-      // Get the Attribute set by testsessionreplication.jsp
-      String attr1 = makeGetWithState(client, baseURL1_ +getURLName);
-      
-      assertEquals("Session still present", attr, attr1);
-   }
-   
-   public void testMaxUnreplicatedInterval2() throws IOException
-   {
-      getLog().debug("Enter testMaxUnreplicatedInterval2");
-
-      String setURLName = "/http-sr/testsessionreplication.jsp";
-      String getURLName = "/http-sr/getattribute.jsp";
-      String versionURLName = "/http-sr/version.jsp";
-
-      // Create an instance of HttpClient.
-      HttpClient client = new HttpClient();
-
-      // Set the session attribute first
-      makeGet(client, baseURL0_ +setURLName);
-      // Get the Attribute set by testsessionreplication.jsp
-      String attr = makeGetWithState(client, baseURL0_ +getURLName);
-      
-      // Sleep 50% of the maxInactiveInterval -- long enough
-      sleepThread(10000);
-      
-      // Access the session without touching any attribute
-      String ver = makeGetWithState(client, baseURL0_ +versionURLName);
-      
-      // Sleep some more, long enough for the session to replicate
-      // if the last request incorrectly caused replication 
-      sleepThread(2000);
-      
-      // Switch servers
-      SessionTestUtil.setCookieDomainToThisServer(client, servers_[1]);
-      
-      String ver1 = makeGetWithState(client, baseURL1_ +versionURLName);
-      
-      assertEquals("Session version count unchanged", ver, ver1);
-      
-      // Get the Attribute set by testsessionreplication.jsp
-      String attr1 = makeGetWithState(client, baseURL1_ +getURLName);
-      
-      assertEquals("Session still present", attr, attr1);
-   }
-
-}

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/testutil/CacheConfigTestSetup.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/testutil/CacheConfigTestSetup.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/testutil/CacheConfigTestSetup.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -72,18 +72,11 @@
    protected void setUp() throws Exception
    {
       if (pojoCaches == null) return;
-      String bind_addr = System.getProperty("jgroups.bind_addr");
-      String mcast_addr = System.getProperty("jgroups.udp.mcast_addr");
-      String mcast_port =  System.getProperty("jgroups.udp.mcast_port");
+      JGroupsSystemPropertySupport jgSupport = new JGroupsSystemPropertySupport();
       
       try
       {
-         System.setProperty("jgroups.bind_addr", System.getProperty("jbosstest.cluster.node1", InetAddress.getLocalHost().getHostAddress()));
-         String udpGroup = System.getProperty("jbosstest.udpGroup", "233.54.54.54");
-         if (udpGroup.trim().length() ==0)
-            udpGroup = "233.54.54.54";
-         System.setProperty("jgroups.udp.mcast_addr", udpGroup);
-         System.setProperty("jgroups.udp.mcast_port", String.valueOf(54545));
+         jgSupport.setUpProperties();
          
          for (int i = 0; i < pojoCaches.length; i++)
          {
@@ -92,18 +85,7 @@
       }
       finally
       {
-         if (bind_addr == null)
-            System.clearProperty("jgroups.bind_addr");
-         else
-            System.setProperty("jgroups.bind_addr", bind_addr);
-         if (mcast_addr == null)
-            System.clearProperty("jgroups.udp.mcast_addr");
-         else
-            System.setProperty("jgroups.udp.mcast_addr", mcast_addr);
-         if (mcast_port == null)
-            System.clearProperty("jgroups.udp.mcast_port");
-         else
-            System.setProperty("jgroups.udp.mcast_port", mcast_port);
+         jgSupport.restoreProperties();
       }
       
       // wait a few seconds so that the cluster stabilize

Deleted: trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsConfigSupport.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsConfigSupport.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsConfigSupport.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -1,72 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, 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.test.cluster.testutil;
-
-/**
- * @author Brian Stansberry
- *
- */
-public class JGroupsConfigSupport
-{
-   private static final String UDP_PORT = "34567";
-   
-   private String bind_address;
-   private String udp_group;
-   private String udp_port;
-   
-   public void setUp()
-   {
-      // Set system properties to properly bind JGroups channels
-      
-      // First, preserve any existing values
-      bind_address = System.getProperty("jgroups.bind_addr");
-      udp_group = System.getProperty("jboss.partition.udpGroup");
-      udp_port = System.getProperty("jboss.partition.udpPort");
-      
-      System.setProperty("jgroups.bind_addr", System.getProperty("jbosstest.cluster.node0", "127.0.0.1"));
-      String grp = System.getProperty("jbosstest.udpGroup");
-      if (grp != null && grp.length() > 0)
-      {
-         System.setProperty("jboss.partition.udpGroup", grp);
-      }
-      System.setProperty("jboss.partition.udpPort", UDP_PORT);
-   }
-   
-   public void tearDown()
-   {      
-      // Restore any system properties we set in setUp
-      if (bind_address == null)
-         System.clearProperty("jgroups.bind_addr");
-      else
-         System.setProperty("jgroups.bind_addr", bind_address);
-      if (udp_group == null)
-         System.clearProperty("jboss.partition.udpGroup");
-      else
-         System.setProperty("jboss.partition.udpGroup", udp_group);
-      
-      if (udp_port == null)
-         System.clearProperty("jboss.partition.udpPort");
-      else
-         System.setProperty("jboss.partition.udpPort", udp_port);
-   }
-}

Added: trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsSystemPropertySupport.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsSystemPropertySupport.java	                        (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/testutil/JGroupsSystemPropertySupport.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.test.cluster.testutil;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Utility class that sets and clears JGroups-related system properties.
+ * 
+ * @author Brian Stansberry
+ */
+public class JGroupsSystemPropertySupport
+{
+   private String bind_addr = System.getProperty("jgroups.bind_addr");
+   private String mcast_addr = System.getProperty("jgroups.udp.mcast_addr");
+   private String mcast_port =  System.getProperty("jgroups.udp.mcast_port");
+   
+   public void setUpProperties() throws UnknownHostException
+   {
+      System.setProperty("jgroups.bind_addr", System.getProperty("jbosstest.cluster.node1", InetAddress.getLocalHost().getHostAddress()));
+      String udpGroup = System.getProperty("jbosstest.udpGroup", "233.54.54.54");
+      if (udpGroup.trim().length() ==0)
+         udpGroup = "233.54.54.54";
+      System.setProperty("jgroups.udp.mcast_addr", udpGroup);
+      System.setProperty("jgroups.udp.mcast_port", String.valueOf(54545));
+   }
+   
+   public void restoreProperties()
+   {
+      if (bind_addr == null)
+         System.clearProperty("jgroups.bind_addr");
+      else
+         System.setProperty("jgroups.bind_addr", bind_addr);
+      if (mcast_addr == null)
+         System.clearProperty("jgroups.udp.mcast_addr");
+      else
+         System.setProperty("jgroups.udp.mcast_addr", mcast_addr);
+      if (mcast_port == null)
+         System.clearProperty("jgroups.udp.mcast_port");
+      else
+         System.setProperty("jgroups.udp.mcast_port", mcast_port);      
+   }
+}

Modified: trunk/testsuite/src/main/org/jboss/test/cluster/testutil/SessionTestUtil.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/testutil/SessionTestUtil.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/testutil/SessionTestUtil.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -92,6 +92,7 @@
                                                  String jvmRoute)
    {
       JBossCacheManager jbcm = new JBossCacheManager(cache);
+      jbcm.setSnapshotMode(SnapshotMode.INSTANT);
       
       MockEngine engine = new MockEngine();
       engine.setJvmRoute(jvmRoute);
@@ -101,10 +102,14 @@
       StandardContext container = new StandardContext();
       container.setName(warName);
       host.addChild(container);
-      jbcm.setContainer(container);
+      container.setManager(jbcm);
+      
+      // Do this after assigning the manager to the container, or else
+      // the container's setting will override ours
+      // Can't just set the container as their config is per minute not per second
       jbcm.setMaxInactiveInterval(maxInactiveInterval);
       
-      jbcm.setSnapshotMode(SnapshotMode.INSTANT);
+      
    
    return jbcm;      
    }
@@ -114,7 +119,9 @@
    {
       Configuration cfg = getConfiguration(local, passivationDir, totalReplication, marshalling);
       PojoCache cache = PojoCacheFactory.createCache(cfg, true);
-      allCaches.add(cache);
+      
+      if (allCaches != null)
+         allCaches.add(cache);
       return cache;
    }
    
@@ -152,12 +159,34 @@
    
    public static JBossWebMetaData createWebMetaData(int maxSessions)
    {
-      return createWebMetaData(maxSessions, false, -1, -1);
-   }
+      return createWebMetaData(ReplicationGranularity.SESSION,
+                               ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET,
+                               maxSessions, false, -1, -1, false, 0);
+   } 
    
    public static JBossWebMetaData createWebMetaData(int maxSessions, boolean passivation,
-                                              int maxIdle, int minIdle)
+         int maxIdle, int minIdle)
    {
+      return createWebMetaData(ReplicationGranularity.SESSION,
+                               ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET,
+                               maxSessions, passivation, maxIdle, minIdle, false, 60);
+   } 
+   
+   public static JBossWebMetaData createWebMetaData(ReplicationGranularity granularity,
+                                                    ReplicationTrigger trigger,boolean batchMode,
+                                                    int maxUnreplicated)
+   {
+      return createWebMetaData(granularity, trigger, -1, false, 
+                               -1, -1, batchMode, maxUnreplicated);
+   } 
+   
+   public static JBossWebMetaData createWebMetaData(ReplicationGranularity granularity,
+                                              ReplicationTrigger trigger,
+                                              int maxSessions, boolean passivation,
+                                              int maxIdle, int minIdle,
+                                              boolean batchMode,
+                                              int maxUnreplicated)
+   {
       JBossWebMetaData webMetaData = new JBossWebMetaData();
       webMetaData.setDistributable(new EmptyMetaData());
       webMetaData.setMaxActiveSessions(new Integer(maxSessions));
@@ -167,8 +196,10 @@
       pcfg.setPassivationMinIdleTime(new Integer(minIdle));
       webMetaData.setPassivationConfig(pcfg);
       ReplicationConfig repCfg = new ReplicationConfig();
-      repCfg.setReplicationGranularity(ReplicationGranularity.SESSION);
-      repCfg.setReplicationTrigger(ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET);
+      repCfg.setReplicationGranularity(granularity);
+      repCfg.setReplicationTrigger(trigger);
+      repCfg.setReplicationFieldBatchMode(Boolean.valueOf(batchMode));
+      repCfg.setMaxUnreplicatedInterval(Integer.valueOf(maxUnreplicated));
       webMetaData.setReplicationConfig(repCfg);
       return webMetaData;
    }

Added: trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/jboss-web.xml
===================================================================
--- trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/jboss-web.xml	                        (rev 0)
+++ trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/jboss-web.xml	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<jboss-web>
+   <replication-config>
+      <max-unreplicated-interval>8</max-unreplicated-interval>
+   </replication-config>
+</jboss-web>

Added: trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/web.xml
===================================================================
--- trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/web.xml	                        (rev 0)
+++ trunk/testsuite/src/resources/cluster/http/http-sr/WEB-INF/web.xml	2008-07-13 13:33:32 UTC (rev 75738)
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+<web-app>
+  <display-name>Welcome to JBoss</display-name>
+  <description>
+     Welcome to JBoss
+  </description>
+  <distributable/>
+
+  <!-- timeout is set to 60 seconds -->
+  <session-config>
+     <session-timeout>1</session-timeout>
+  </session-config>
+</web-app>

Modified: trunk/testsuite/src/resources/cluster/http/testsessionreplication.jsp
===================================================================
--- trunk/testsuite/src/resources/cluster/http/testsessionreplication.jsp	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/resources/cluster/http/testsessionreplication.jsp	2008-07-13 13:33:32 UTC (rev 75738)
@@ -3,8 +3,8 @@
 <center>
 <% String id=request.getSession().getId();
    session.setAttribute("TEST_HTTP",id);
-   // Expire after 20 secs so we can more promptly run timeout tests 
-   session.setMaxInactiveInterval(20);
+   // Expire after 10 secs so we can more promptly run timeout tests 
+   session.setMaxInactiveInterval(10);
 %>
 <p>Storing session id in attribute with id: <%=id%>
 

Deleted: trunk/testsuite/src/resources/cluster/http/web.xml
===================================================================
--- trunk/testsuite/src/resources/cluster/http/web.xml	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/testsuite/src/resources/cluster/http/web.xml	2008-07-13 13:33:32 UTC (rev 75738)
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
-
-<!DOCTYPE web-app
-    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
-    "http://java.sun.com/dtd/web-app_2_3.dtd">
-
-<web-app>
-  <display-name>Welcome to JBoss</display-name>
-  <description>
-     Welcome to JBoss
-  </description>
-  <distributable/>
-
-  <!-- timeout is set to 60 seconds -->
-  <session-config>
-     <session-timeout>1</session-timeout>
-  </session-config>
-</web-app>

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/deployers/ClusteringDefaultsDeployer.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/deployers/ClusteringDefaultsDeployer.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/deployers/ClusteringDefaultsDeployer.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -54,6 +54,7 @@
    private ReplicationTrigger replicationTrigger;
    private boolean replicationFieldBatchMode = true;
    private Boolean useJK;
+   private int maxUnreplicatedInterval;
    private boolean useSessionPassivation;
    private int passivationMinIdleTime = IGNORED;
    private int passivationMaxIdleTime = IGNORED;
@@ -195,6 +196,16 @@
       this.passivationMaxIdleTime = passivationMaxIdleTime;
    }
 
+   public int getMaxUnreplicatedInterval()
+   {
+      return maxUnreplicatedInterval;
+   }
+
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval)
+   {
+      this.maxUnreplicatedInterval = maxUnreplicatedInterval;
+   }
+
    /**
     * Injects the configured default property values into any
     * {@link JBossWebMetaData} attached to <code>unit</code> if the 
@@ -269,6 +280,11 @@
                                                            ? fieldGranularityCacheName : cacheName;
          repCfg.setCacheName(cacheConfig);
       }
+      
+      if (repCfg.getMaxUnreplicatedInterval() == null)
+      {
+         repCfg.setMaxUnreplicatedInterval(new Integer(maxUnreplicatedInterval));
+      }
    }
    
 

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/AttributeBasedClusteredSession.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -111,18 +111,8 @@
    /**
     * Overrides the superclass version to read in the attributes.
     */
-   public synchronized void processSessionRepl()
+   protected synchronized void replicateAttributes()
    {
-      // Replicate the metadata first. Note this will be lightweight since many  
-      // of the fields are transient and the attribute map isn't included.
-      if (log.isTraceEnabled())
-      {
-         log.trace("processSessionRepl(): session is dirty. Will increment " +
-                "version from: " + getVersion() + " and replicate.");
-      }
-      this.incrementVersion();
-      proxy_.putSession(realId, this);
-
       // Go thru the attribute change list
       
       if (isSessionAttributeMapDirty())
@@ -154,11 +144,6 @@
          
          clearAttrChangedMaps();
       }
-      
-      sessionAttributesDirty = false;
-      sessionMetadataDirty = false;
-      
-      updateLastReplicated();
    }
 
    public void removeMyself()

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -150,14 +150,6 @@
     * Timestamp when we were last replicated.
     */
    protected transient long lastReplicated;
-
-   /**
-    * Maximum percentage of the inactive interval this session
-    * should be allowed to go unreplicated if access to the
-    * session doesn't mark it as dirty. Drives the calculation
-    * of maxUnreplicatedInterval.
-    */
-   protected transient int maxUnreplicatedFactor = 25;
    
    /**
     * Maximum number of milliseconds this session
@@ -166,6 +158,9 @@
     */
    protected transient long maxUnreplicatedInterval;
    
+   /** True if maxUnreplicatedInterval is 0 or less than maxInactiveInterval */
+   protected transient boolean alwaysReplicateTimestamp = true;
+   
    /**
     * Whether any of this session's attributes implement
     * HttpSessionActivationListener.
@@ -189,7 +184,7 @@
       invalidationPolicy = manager.getReplicationTrigger();
       this.useJK = useJK;
       this.firstAccess = true;
-      calcMaxUnreplicatedInterval();
+      checkAlwaysReplicateTimestamp();
    }
 
    /**
@@ -312,70 +307,16 @@
    public int incrementVersion()
    {
       return version++;
-   }
+   }   
 
    /**
-    * Gets the maximum percentage of the <code>maxInactiveInterval</code>
-    * beyond which the session timestamp should be replicated upon access even 
-    * if the session isn't dirty.  Used to ensure that even a read-only session 
-    * gets replicated before it expires, so that it isn't removed from other
-    * nodes.
-    * <p>
-    * Default value is <code>25</code>.
-    * </p>
-    * <p>
-    * <strong>NOTE:</strong> If a timestamp hasn't been replicated in the last
-    * 60 seconds, the timestamp will be replicated, irregardless of this
-    * setting.  So, this setting really only serves to provide a lower setting.
-    * </p>
-    * 
-    * @return  an int between 1 and 100, or -1 if replicating on access is
-    *          disabled
-    */
-   public int getMaxUnreplicatedFactor()
-   {
-      return maxUnreplicatedFactor;
-   }
-
-   /**
-    * Sets the maximum percentage of the <code>maxInactiveInterval</code>
-    * beyond which a session should be replicated upon access even if it 
-    * isn't dirty.  Used to ensure that even a read-only session gets 
-    * replicated before it expires, so that it isn't removed from other
-    * nodes.
-    * <p>
-    * Default value is <code>25</code>.
-    * </p>
-    * <p>
-    * <strong>NOTE:</strong> If a timestamp hasn't been replicated in the last
-    * 60 seconds, the timestamp will be replicated, irregardless of this
-    * setting.  So, this setting really only serves to provide a lower setting.
-    * </p>
-    * 
-    * @param maxUnreplicatedFactor  an int between 1 and 100, or -1 to
-    *                               disable replicating on access
-    * 
-    * @throws IllegalArgumentException if the factor isn't -1 or between
-    *                                  1 and 100
-    */
-   public void setMaxUnreplicatedFactor(int factor)
-   {
-      if ((factor != -1 && factor < 1) || factor > 100)
-         throw new IllegalArgumentException("Invalid factor " + factor +
-                                   " -- must be between 1 and 100 or -1");
-      this.maxUnreplicatedFactor = factor;
-      calcMaxUnreplicatedInterval();
-   }
-   
-
-   /**
     * Overrides the superclass to calculate 
     * {@link #getMaxUnreplicatedInterval() maxUnreplicatedInterval}.
     */
    public void setMaxInactiveInterval(int interval)
    {
       super.setMaxInactiveInterval(interval);
-      calcMaxUnreplicatedInterval();
+      checkAlwaysReplicateTimestamp();
       sessionMetadataDirty();
    }
 
@@ -402,30 +343,28 @@
       return maxUnreplicatedInterval;
    }
    
-   public boolean getExceedsMaxUnreplicatedInterval()
+   public void setMaxUnreplicatedInterval(long interval)
    {
-      boolean result = (invalidationPolicy == ReplicationTrigger.ACCESS);
+      this.maxUnreplicatedInterval = Math.max(interval, -1);
+      checkAlwaysReplicateTimestamp();
+   }
+   
+   public boolean getMustReplicateTimestamp()
+   {
+      // If the access times are the same, access() was never called
+      // on the session
+      boolean touched = this.thisAccessedTime != this.lastAccessedTime;
+      boolean exceeds = alwaysReplicateTimestamp && touched;
       
-      if (!result && maxUnreplicatedInterval > 0) // -1 means ignore; 0 means expire now
+      if (!exceeds && touched && maxUnreplicatedInterval > 0) // -1 means ignore
       {
-         result = ((System.currentTimeMillis() - lastReplicated) >= maxUnreplicatedInterval);
+         long unrepl = System.currentTimeMillis() - lastReplicated;
+         exceeds = (unrepl >= maxUnreplicatedInterval);
       }      
       
-      return result;
+      return exceeds;
    }
    
-   private void calcMaxUnreplicatedInterval()
-   {
-      if (maxInactiveInterval < 0 || maxUnreplicatedFactor < 0)
-         maxUnreplicatedInterval = -1;
-      else
-      {
-         // Ignoring casting would be (mII * 1000) * (mUF / 100)
-         int interval = maxInactiveInterval * maxUnreplicatedFactor * 10;
-         maxUnreplicatedInterval = Math.min(60000, interval);
-      }
-   }
-   
    public SessionTimestamp getSessionTimestamp()
    {
       this.timestamp.timestamp = this.thisAccessedTime;
@@ -1025,8 +964,8 @@
       version = 0;
       hasActivationListener = null;
       lastReplicated = 0;
-      maxUnreplicatedFactor = 80;
-      calcMaxUnreplicatedInterval();
+      maxUnreplicatedInterval = 0;
+      alwaysReplicateTimestamp = true;
    }
    
    /**
@@ -1167,6 +1106,16 @@
       // access cannot be the first.
       this.firstAccess = false;
       
+      // We don't know when we last replicated our timestamp. We may be
+      // getting called due to activation, not deserialization after
+      // replication, so this.timestamp may be after the last replication.
+      // So use the creation time as a conservative guesstimate.  Only downside 
+      // is we may replicate a timestamp earlier than we need to, which is not
+      // a heavy cost.
+      this.lastReplicated = this.creationTime;
+      
+      checkAlwaysReplicateTimestamp();
+      
       // TODO uncomment when work on JBAS-1900 is completed      
 //      // Session notes -- for FORM auth apps, allow replicated session 
 //      // to be used without requiring a new login
@@ -1389,6 +1338,14 @@
                   attribute instanceof Boolean);
    }
    
+   private void checkAlwaysReplicateTimestamp()
+   {
+      this.alwaysReplicateTimestamp = 
+         (maxUnreplicatedInterval == 0 
+            || (maxUnreplicatedInterval > 0 && maxInactiveInterval >= 0 
+                  && maxUnreplicatedInterval > (maxInactiveInterval * 1000)));
+   }
+   
    /**
     * Encapsulates the "thisAccessedTime" timestamp. The wrapped timestamp long
     * can be mutated, allowing the same object to always be stored in 

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -46,6 +46,8 @@
    public JBossCacheClusteredSession(JBossCacheManager manager)
    {
       super(manager, manager.getUseJK());
+      int maxUnrep = manager.getMaxUnreplicatedInterval() * 1000;
+      setMaxUnreplicatedInterval(maxUnrep);
       establishProxy();
    }
 
@@ -136,11 +138,23 @@
       this.incrementVersion();
       proxy_.putSession(realId, this);
       
+      // Allow subclasses to replicate attributes if needed
+      replicateAttributes();
+      
       sessionAttributesDirty = false;
       sessionMetadataDirty = false;
       
       updateLastReplicated();
    }
+   
+   /**
+    * Extension point for subclasses to handle replication of attributes.
+    * This default implementation does nothing.
+    */
+   protected void replicateAttributes()
+   {
+      // no-op
+   }
 
    /**
     * Overrides the superclass impl by doing nothing if <code>localCall</code>

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -153,6 +153,8 @@
    
    /** Did we get our cache from a cache manager */
    private boolean cacheFromCacheManager_;
+   
+   private int maxUnreplicatedInterval_ = -1;
 
    //  ----------------------------------------------------------  Constructors
 
@@ -204,6 +206,12 @@
       Integer snapshotInt = repCfg.getSnapshotInterval();
       setSnapshotInterval(snapshotInt == null ? 0 : snapshotInt.intValue());
       
+      Integer maxUnrep = repCfg.getMaxUnreplicatedInterval();
+      if (maxUnrep != null)
+      {
+         this.maxUnreplicatedInterval_ = maxUnrep.intValue();
+      }
+      
       log_.debug("init(): replicationGranularity_ is " + replicationGranularity_ +
          " and replicationFieldBatchMode is " + replicationFieldBatchMode_ +
          " and useJK is " + useJK_ +
@@ -449,6 +457,17 @@
       this.replicationFieldBatchMode_ = Boolean.valueOf(replicationFieldBatchMode);
    }
 
+   public int getMaxUnreplicatedInterval()
+   {
+      return maxUnreplicatedInterval_;
+   }
+
+   public void setMaxUnreplicatedInterval(int maxUnreplicatedInterval)
+   {
+      this.maxUnreplicatedInterval_ = maxUnreplicatedInterval;
+   }  
+   
+
    // JBossCacheManagerMBean-methods -------------------------------------
 
    public void expireSession(String sessionId)
@@ -821,7 +840,7 @@
             }
 
             if (session.isValid() &&
-                  (session.isSessionDirty() || session.getExceedsMaxUnreplicatedInterval()))
+                  (session.isSessionDirty() || session.getMustReplicateTimestamp()))
             {
                String realId = session.getRealId();
 
@@ -1464,6 +1483,11 @@
          long now = System.currentTimeMillis();
          Map unloaded = new HashMap(unloadedSessions_);
          Set entries = unloaded.entrySet();
+         // We may have not gotten replication of a timestamp for requests 
+         // that occurred w/in maxUnreplicatedInterval_ of the previous
+         // request. So we add a grace period to avoid flushing a session early
+         // and permanently losing part of its node structure in JBoss Cache.
+         long maxUnrep = maxUnreplicatedInterval_ < 0 ? 60 : maxUnreplicatedInterval_;
          for (Iterator it = entries.iterator(); it.hasNext(); )
          {
             Map.Entry entry = (Map.Entry) it.next();
@@ -1476,7 +1500,7 @@
             long elapsed = (now - osu.updateTime);
             try
             {
-               if (expire && elapsed >= (osu.maxInactive * 1000L))
+               if (expire && elapsed >= (osu.maxInactive + maxUnrep) * 1000L)
                {
                   proxy_.removeSessionLocal(realId, osu.owner);
                   unloadedSessions_.remove(realId);

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManagerMBean.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -117,6 +117,45 @@
     * is used.
     */
    int getSnapshotInterval();
+
+   /**
+    * Get the maximum interval between requests, in seconds, after which a
+    * request will trigger replication of the session's metadata regardless
+    * of whether the request has otherwise made the session dirty. Such 
+    * replication ensures that other nodes in the cluster are aware of a 
+    * relatively recent value for the session's timestamp and won't incorrectly
+    * expire an unreplicated session upon failover.
+    * <p/>
+    * Default value is <code>-1</code>.
+    * <p/>
+    * The cost of the metadata replication depends on the configured
+    * {@link #setReplicationGranularityString(String) replication granularity}.
+    * With <code>SESSION</code>, the sesssion's attribute map is replicated 
+    * along with the metadata, so it can be fairly costly.  With other 
+    * granularities, the metadata object is replicated separately from the
+    * attributes and only contains a String, and a few longs, ints and booleans.
+    * 
+    * @return the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
+   int getMaxUnreplicatedInterval();
+
+   /**
+    * Sets the maximum interval between requests, in seconds, after which a
+    * request will trigger replication of the session's metadata regardless
+    * of whether the request has otherwise made the session dirty.
+    * 
+    * @param  maxUnreplicatedInterval  
+    *         the maximum interval since last replication after which a request
+    *         will trigger session metadata replication. A value of 
+    *         <code>0</code> means replicate metadata on every request; a value 
+    *         of <code>-1</code> means never replicate metadata unless the 
+    *         session is otherwise dirty.
+    */
+   void setMaxUnreplicatedInterval(int maxUnreplicatedInterval);
    
    /**
     * Lists all session ids known to this manager, including those in the 

Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheService.java	2008-07-13 13:33:32 UTC (rev 75738)
@@ -330,11 +330,13 @@
       
       Map map = new HashMap();
       map.put(VERSION_KEY, new Integer(session.getVersion()));
-      map.put(TIMESTAMP_KEY, session.getSessionTimestamp());
       
+      boolean replicateTimestamp = false;
+      
       if (session.isSessionMetadataDirty())
       {   
-         map.put(METADATA_KEY, session.getSessionMetadata());         
+         map.put(METADATA_KEY, session.getSessionMetadata()); 
+         replicateTimestamp = true;
       }
      
       if (session.isSessionAttributeMapDirty())
@@ -348,9 +350,16 @@
 //               map.put(ATTRIBUTE_KEY, attrs);
 //            else
             map.put(ATTRIBUTE_KEY, getMarshalledValue(attrs));
-         }
+         } 
+         
+         replicateTimestamp = true;
       }
       
+      if (replicateTimestamp || session.getMustReplicateTimestamp())
+      {
+         map.put(TIMESTAMP_KEY, session.getSessionTimestamp());
+      }
+      
       cacheWrapper_.put(fqn, map);
    }
 

Modified: trunk/tomcat/src/resources/war-deployers-beans.xml
===================================================================
--- trunk/tomcat/src/resources/war-deployers-beans.xml	2008-07-13 12:04:20 UTC (rev 75737)
+++ trunk/tomcat/src/resources/war-deployers-beans.xml	2008-07-13 13:33:32 UTC (rev 75738)
@@ -79,11 +79,34 @@
       -->
       <!-- 
       <property name="useJK">false</property>
-      -->
       
       <property name="useSessionPassivation">false</property>
       <property name="passivationMaxIdleTime">-1</property>  
       <property name="passivationMinIdleTime">-1</property>
+      -->
+
+      <!--
+       Determines the maximum interval between requests, in seconds, after 
+       which a request will trigger replication of the session's timestamp 
+       regardless of whether the request has otherwise made the session dirty.  
+       Such replication ensures that other nodes in the cluster are aware of 
+       the most recent value for the session's timestamp and won't incorrectly 
+       expire an unreplicated session upon failover. It also results in correct 
+       values for HttpSession.getLastAccessedTime() calls following failover.
+
+       The cost of timestamp replication is considerably lower in JBoss AS 5
+       than it is in earlier versions since replicating a timestamp does not
+       necessitate replicating any other data.
+   
+       A value of 0 means the metadata will be replicated whenever the session is
+       accessed.  A value of -1 means the metadata will be replicated only if some
+       other activity during the request (e.g. modifying an attribute) has
+       resulted in other replication work involving the session. A positive value
+       greater than the HttpSession.getMaxInactiveInterval() value will be treated 
+       as a likely misconfiguration and converted to 0; i.e. replicate the 
+       metadata on every request.
+      -->
+      <property name="maxUnreplicatedInterval">60</property>
       
    </bean>  
     




More information about the jboss-cvs-commits mailing list