[jboss-cvs] JBossAS SVN: r91181 - in branches/JBPAPP_5_0: testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test and 12 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Jul 13 17:46:55 EDT 2009


Author: bstansberry at jboss.com
Date: 2009-07-13 17:46:54 -0400 (Mon, 13 Jul 2009)
New Revision: 91181

Added:
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/DriverManagerPersistentStoreUnitTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMaxUnreplicatedIntervalTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMemoryLeakTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionCountUnitTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionNotificationPolicyTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/PersistentManagerCrossContextCallsTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetupDelegate.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DelegatingClusteredTestCase.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/TestSetupDelegate.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossCacheConfigTestSetupDelegate.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/ManagerOverrideDisabler.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockDataSource.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockOutgoingSessionData.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentSessionTestUtil.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreSetupDelegate.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTableSetup.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTestSetup.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/SimplePersistentStoreTestSetup.java
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/META-INF/
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/META-INF/application.xml
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/WEB-INF/
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/WEB-INF/context.xml
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/disable-manager-override-jboss-beans.xml
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/httpsession-ds.xml
   branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/rdbmsstore-tablesetup-jboss-beans.xml
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/AskSessionOutdatedSessionChecker.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OutdatedSessionChecker.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OwnedSessionUpdate.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AbstractPersistentManager.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AlwaysTrueOutdatedSessionChecker.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentManager.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentStore.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DriverManagerPersistentStore.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/ExtendedDistributedCacheManager.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/IncomingDistributableSessionDataImpl.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStore.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManager.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManagerFactory.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/RDBMSStoreBase.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/TimestampBasedOutdatedSessionChecker.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/VersionBasedOutdatedSessionChecker.java
Modified:
   branches/JBPAPP_5_0/testsuite/imports/sections/cluster.xml
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetup.java
   branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossClusteredWebTestCase.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/DeployerConfig.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployment.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
   branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java
   branches/JBPAPP_5_0/tools/etc/buildmagic/modules.ent
Log:
[JBPAPP-2257] HA Web Sessions via Database Persistence

Modified: branches/JBPAPP_5_0/testsuite/imports/sections/cluster.xml
===================================================================
--- branches/JBPAPP_5_0/testsuite/imports/sections/cluster.xml	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/testsuite/imports/sections/cluster.xml	2009-07-13 21:46:54 UTC (rev 91181)
@@ -602,8 +602,17 @@
          <fileset dir="${build.lib}">
             <include name="cluster-clleak-ejb.jar"/>
          </fileset>
-       </ear>     
+       </ear> 
       
+      <jar destfile="${build.lib}/rdbmsstore-tablesetup.jar">
+         <metainf dir="${build.resources}/cluster/persistent">
+            <include name="rdbmsstore-tablesetup-jboss-beans.xml"/>
+         </metainf>
+         <fileset dir="${build.classes}">
+            <include name="org/jboss/test/cluster/web/persistent/PersistentStoreTableSetup.class"/>
+         </fileset>
+      </jar>    
+      
    </target>
  
    <!-- testbeancluster test -->
@@ -720,7 +729,81 @@
            fullpath="META-INF/ejb-jar.xml" includes="pooledha-ejb-jar.xml"/>
         <zipfileset dir="${build.resources}/cluster/ejb2/basic"
            fullpath="META-INF/jboss.xml" includes="pooledha-jboss.xml"/>
-     </jar>
+     </jar> 
+      
+      <!-- DataSourcePersistentManager Tests -->
+      <copy todir="${build.lib}"
+         file="${build.resources}/cluster/persistent/httpsession-ds.xml"
+         overwrite="true"/>
+      
+      <jar destfile="${build.lib}/disable-manager-override.beans">
+         <fileset dir="${build.classes}">
+            <include name="org/jboss/test/cluster/web/persistent/ManagerOverrideDisabler.class"/>
+         </fileset>
+         <metainf dir="${build.resources}/cluster/persistent/">
+            <include name="disable-manager-override-jboss-beans.xml"/>
+         </metainf>
+      </jar>
+      
+      <!-- build http-cross-ctx-first-persistent.jar -->
+      <war warfile="${build.lib}/http-cross-ctx-first-persistent.war"
+         webxml="${build.resources}/cluster/http/http-cross-ctx-first/WEB-INF/web.xml">
+         <webinf dir="${build.resources}/cluster/persistent/WEB-INF">
+            <include name="context.xml"/>
+         </webinf>
+          <classes dir="${build.classes}">
+             <include name="org/jboss/test/cluster/web/Person.class"/>
+             <include name="org/jboss/test/cluster/web/CacheHelper*"/>
+             <include name="org/jboss/test/cluster/web/BindingListener.class"/>
+             <include name="org/jboss/test/cluster/web/DeserializationSensor.class"/>
+          </classes>
+         <fileset dir="${build.resources}/cluster/http/http-cross-ctx-first">
+            <include name="*.jsp"/>
+         </fileset>
+      </war>
+      
+      <!-- build http-cross-ctx-second-persistent.jar -->
+      <war warfile="${build.lib}/http-cross-ctx-second-persistent.war"
+         webxml="${build.resources}/cluster/http/http-cross-ctx-second/WEB-INF/web.xml">
+         <webinf dir="${build.resources}/cluster/persistent/WEB-INF">
+            <include name="context.xml"/>
+         </webinf>
+          <classes dir="${build.classes}">
+             <include name="org/jboss/test/cluster/web/Person.class"/>
+             <include name="org/jboss/test/cluster/web/CacheHelper*"/>
+             <include name="org/jboss/test/cluster/web/BindingListener.class"/>
+             <include name="org/jboss/test/cluster/web/DeserializationSensor.class"/>
+          </classes>
+         <fileset dir="${build.resources}/cluster/http/http-cross-ctx-second">
+            <include name="*.jsp"/>
+         </fileset>
+      </war>
+      
+      <!-- build http-cross-ctx-third-persistent.jar -->
+      <war warfile="${build.lib}/http-cross-ctx-third-persistent.war"
+         webxml="${build.resources}/cluster/http/http-cross-ctx-third/WEB-INF/web.xml">
+         <webinf dir="${build.resources}/cluster/persistent/WEB-INF">
+            <include name="context.xml"/>
+         </webinf>
+          <classes dir="${build.classes}">
+             <include name="org/jboss/test/cluster/web/Person.class"/>
+             <include name="org/jboss/test/cluster/web/CacheHelper*"/>
+             <include name="org/jboss/test/cluster/web/BindingListener.class"/>
+             <include name="org/jboss/test/cluster/web/DeserializationSensor.class"/>
+          </classes>
+         <fileset dir="${build.resources}/cluster/http/http-cross-ctx-third">
+            <include name="*.jsp"/>
+         </fileset>
+      </war>
+        
+      <ear earfile="${build.lib}/http-cross-ctx-persistent.ear"
+         appxml="${build.resources}/cluster/persistent/META-INF/application.xml">
+         <fileset dir="${build.lib}">
+            <include name="http-cross-ctx-first-persistent.war"/>
+            <include name="http-cross-ctx-second-persistent.war"/>
+            <include name="http-cross-ctx-third-persistent.war"/>
+         </fileset>
+      </ear>
    </target>  
  
 
@@ -828,7 +911,7 @@
          <fileset dir="${build.classes}">
             <include name="org/jboss/test/cluster/rspfilter/*"/>
          </fileset>
-      </zip>    
+      </zip>  
       
    </target>  
 </project>

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/DriverManagerPersistentStoreUnitTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/DriverManagerPersistentStoreUnitTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/DriverManagerPersistentStoreUnitTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,758 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.defaultcfg.simpleweb.test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import org.jboss.test.cluster.web.persistent.MockOutgoingSessionData;
+import org.jboss.test.cluster.web.persistent.SimplePersistentStoreTestSetup;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData;
+import org.jboss.web.tomcat.service.session.persistent.DriverManagerPersistentStore;
+import org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase;
+
+/**
+ * Unit tests for {@link DriverManagerPersistentStore}, although really more of
+ * a test of its abstract superclass RDBMSStoreBase where we use the 
+ * DriverManager-based subclass as a simple way to get a concrete implementation.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class DriverManagerPersistentStoreUnitTestCase extends TestCase
+{
+   private static final String CONNECTION_URL = "jdbc:hsqldb:hsql://localhost:1701";
+   private static final String CONTEXT_PATH = "localhost/test";
+
+   private static AtomicInteger id = new AtomicInteger();
+   
+   private DriverManagerPersistentStore testee;
+   
+   /**
+    * @param name
+    */
+   public DriverManagerPersistentStoreUnitTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      return SimplePersistentStoreTestSetup.getDeploySetup(DriverManagerPersistentStoreUnitTestCase.class);
+   }
+   
+   private static String nextId()
+   {
+      return "session" + id.incrementAndGet();
+   }
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+      
+      testee = new DriverManagerPersistentStore();
+      testee.setDriverName(org.hsqldb.jdbcDriver.class.getName());
+      testee.setConnectionURL(CONNECTION_URL);
+      testee.setConnectionName("sa");
+      testee.setName(CONTEXT_PATH);
+   }
+   
+   @Override
+   protected void tearDown() throws Exception
+   {
+      try
+      {
+         if (testee != null && testee.isStarted())
+         {
+            testee.stop();
+         }
+      }
+      finally
+      {
+         super.tearDown();
+      }
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.DriverManagerPersistentStore#getInfo()}.
+    */
+   public void testGetInfo()
+   {
+      testee.start();
+      assertEquals(testee.getStoreName() + "/1.0", testee.getInfo());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.DriverManagerPersistentStore#getStoreName()}.
+    */
+   public void testGetStoreName()
+   {
+      assertEquals(testee.getClass().getSimpleName(), testee.getStoreName());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.DriverManagerPersistentStore#setConnectionURL(java.lang.String)}.
+    */
+   public void testConnectionURL()
+   {
+      assertEquals(CONNECTION_URL, testee.getConnectionURL());
+      testee.setConnectionURL("blah");
+      assertEquals("blah", testee.getConnectionURL());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.DriverManagerPersistentStore#setDriverName(java.lang.String)}.
+    */
+   public void testDriverName()
+   {
+      assertEquals(org.hsqldb.jdbcDriver.class.getName(), testee.getDriverName());
+      testee.setDriverName("blah");
+      assertEquals("blah", testee.getDriverName());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#getName()}.
+    */
+   public void testName()
+   {
+      assertEquals(CONTEXT_PATH, testee.getName());
+      testee.setName("blah");
+      assertEquals("blah", testee.getName());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setConnectionName(java.lang.String)}.
+    */
+   public void testConnectionName()
+   {
+      assertEquals("sa", testee.getConnectionName());
+      testee.setConnectionName("blah");
+      assertEquals("blah", testee.getConnectionName());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setConnectionPassword(java.lang.String)}.
+    */
+   public void testConnectionPassword()
+   {
+      assertNull(testee.getConnectionPassword());
+      testee.setConnectionPassword("blah");
+      assertEquals("blah", testee.getConnectionPassword());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionTable(java.lang.String)}.
+    */
+   public void testSessionTable()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_TABLE, testee.getSessionTable());
+      testee.setSessionTable("blah");
+      assertEquals("blah", testee.getSessionTable());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionAppCol(java.lang.String)}.
+    */
+   public void testSessionAppCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_APP_COL, testee.getSessionAppCol());
+      testee.setSessionAppCol("blah");
+      assertEquals("blah", testee.getSessionAppCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionIdCol(java.lang.String)}.
+    */
+   public void testSessionIdCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_ID_COL, testee.getSessionIdCol());
+      testee.setSessionIdCol("blah");
+      assertEquals("blah", testee.getSessionIdCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionFullIdCol(java.lang.String)}.
+    */
+   public void testSessionFullIdCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_FULLID_COL, testee.getSessionFullIdCol());
+      testee.setSessionFullIdCol("blah");
+      assertEquals("blah", testee.getSessionFullIdCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionCreationTimeCol(java.lang.String)}.
+    */
+   public void testSessionCreationTimeCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_CREATION_TIME_COL, testee.getSessionCreationTimeCol());
+      testee.setSessionCreationTimeCol("blah");
+      assertEquals("blah", testee.getSessionCreationTimeCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionMaxInactiveCol(java.lang.String)}.
+    */
+   public void testSessionMaxInactiveCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_MAX_INACTIVE_COL, testee.getSessionMaxInactiveCol());
+      testee.setSessionMaxInactiveCol("blah");
+      assertEquals("blah", testee.getSessionMaxInactiveCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionNewCol(java.lang.String)}.
+    */
+   public void testSessionNewCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_ISNEW_COL, testee.getSessionNewCol());
+      testee.setSessionNewCol("blah");
+      assertEquals("blah", testee.getSessionNewCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionVersionCol(java.lang.String)}.
+    */
+   public void testSessionVersionCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_VERSION_COL, testee.getSessionVersionCol());
+      testee.setSessionVersionCol("blah");
+      assertEquals("blah", testee.getSessionVersionCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionLastAccessedCol(java.lang.String)}.
+    */
+   public void testSessionLastAccessedCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_LAST_ACCESSED_COL, testee.getSessionLastAccessedCol());
+      testee.setSessionLastAccessedCol("blah");
+      assertEquals("blah", testee.getSessionLastAccessedCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionValidCol(java.lang.String)}.
+    */
+   public void testSessionValidCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_ISVALID_COL, testee.getSessionValidCol());
+      testee.setSessionValidCol("blah");
+      assertEquals("blah", testee.getSessionValidCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setSessionMetadataCol(java.lang.String)}.
+    */
+   public void testSessionMetadataCol()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_METADATA_COL, testee.getSessionMetadataCol());
+      testee.setSessionMetadataCol("blah");
+      assertEquals("blah", testee.getSessionMetadataCol());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#setCleanupInterval(int)}.
+    */
+   public void testSetCleanupInterval()
+   {
+      assertEquals(RDBMSStoreBase.DEFAULT_CLEANUP_INTERVAL, testee.getCleanupInterval());
+      testee.setCleanupInterval(22);
+      assertEquals(22, testee.getCleanupInterval());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#clear()}.
+    */
+   public void testClear()
+   {
+      testee.start();
+      
+      int existing = testee.getSize();
+      
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      assertEquals(Integer.valueOf(0), testee.getSessionVersion(id));
+      
+      md = new DistributableSessionMetadata();
+      String id2 = nextId();
+      md.setId(id2 + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      ts = Long.valueOf(md.getCreationTime() + 1); 
+      attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      sessionData = new MockOutgoingSessionData(id2, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      assertEquals(Integer.valueOf(0), testee.getSessionVersion(id2));
+      
+      assertEquals(2 + existing, testee.getSize());
+      
+      testee.clear();
+      
+      assertNull(testee.getSessionVersion(id));      
+      assertNull(testee.getSessionVersion(id2));
+      
+      assertEquals(0, testee.getSize());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#getSessionIds()}.
+    */
+   public void testGetSessionIds()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      md = new DistributableSessionMetadata();
+      String id2 = nextId();
+      md.setId(id2 + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      ts = Long.valueOf(md.getCreationTime() + 1); 
+      attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      sessionData = new MockOutgoingSessionData(id2, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      Set<String> ids = testee.getSessionIds();
+      assertNotNull(ids);
+      assertTrue(ids.contains(id));
+      assertTrue(ids.contains(id2));
+      assertEquals(2, ids.size());
+      
+      testee.remove(id);
+      
+      ids = testee.getSessionIds();
+      assertNotNull(ids);
+      assertFalse(ids.contains(id));
+      assertTrue(ids.contains(id2));
+      assertEquals(1, ids.size());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#getSessionData(java.lang.String, boolean)}.
+    */
+   public void testGetSessionData()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(0, incoming.getVersion());
+      assertEquals(md.getCreationTime() + 1, incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertTrue(incoming.providesSessionAttributes());
+      assertEquals(attrs, incoming.getSessionAttributes());
+      
+      incoming = testee.getSessionData(id, false);
+      assertEquals(0, incoming.getVersion());
+      assertEquals(md.getCreationTime() + 1, incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertFalse(incoming.providesSessionAttributes());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#remove(java.lang.String)}.
+    */
+   public void testRemove()
+   {
+      testee.start();
+      
+      int existing = testee.getSize();
+      
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      testee.remove(id);
+      
+      assertNull(testee.getSessionData(id, false));
+      assertNull(testee.getSessionData(id, true));
+      assertNull(testee.getSessionVersion(id));
+      assertNull(testee.getSessionTimestamp(id));
+      
+      Set<String> ids = testee.getSessionIds();
+      assertNotNull(ids);
+      assertFalse(ids.contains(id));
+      assertEquals(existing, ids.size());
+      
+      assertEquals(existing, testee.getSize());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#storeSessionData(org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData)}.
+    */
+   public void testInsertSessionData()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(0, incoming.getVersion());
+      assertEquals(md.getCreationTime() + 1, incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertTrue(incoming.providesSessionAttributes());
+      assertEquals(attrs, incoming.getSessionAttributes());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#storeSessionData(org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData)}.
+    */
+   public void testInsertSessionDataNullAttributes()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = null;
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(0, incoming.getVersion());
+      assertEquals(md.getCreationTime() + 1, incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      Map<String, Object> map = incoming.getSessionAttributes();
+      assertNotNull(map);
+      assertEquals(0, map.size());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#storeSessionData(org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData)}.
+    */
+   public void testFullUpdateSessionData()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      md.setNew(false);
+      md.setMaxInactiveInterval(20000);
+      attrs.put("key", "newvalue");
+      ts = Long.valueOf(System.currentTimeMillis());
+      sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(1, incoming.getVersion());
+      assertEquals(ts.longValue(), incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertTrue(incoming.providesSessionAttributes());
+      assertEquals(attrs, incoming.getSessionAttributes());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#storeSessionData(org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData)}.
+    */
+   public void testAttributeUpdateSessionData()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      attrs.put("key", "newvalue");
+      ts = Long.valueOf(System.currentTimeMillis());
+      sessionData = new MockOutgoingSessionData(id, 1, ts, null, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(1, incoming.getVersion());
+      assertEquals(ts.longValue(), incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertTrue(incoming.providesSessionAttributes());
+      assertEquals(attrs, incoming.getSessionAttributes());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#storeSessionData(org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData)}.
+    */
+   public void testMetadataUpdateSessionData()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      md.setNew(false);
+      md.setMaxInactiveInterval(20000);
+      ts = Long.valueOf(System.currentTimeMillis());
+      sessionData = new MockOutgoingSessionData(id, 1, ts, md, null);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(1, incoming.getVersion());
+      assertEquals(ts.longValue(), incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertTrue(incoming.providesSessionAttributes());
+      assertEquals(attrs, incoming.getSessionAttributes());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#storeSessionData(org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData)}.
+    */
+   public void testSimpleUpdateSessionData()
+   {
+      testee.start();
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      ts = Long.valueOf(System.currentTimeMillis());
+      sessionData = new MockOutgoingSessionData(id, 1, ts, null, null);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(1, incoming.getVersion());
+      assertEquals(ts.longValue(), incoming.getTimestamp());
+      assertEquals(md.getId(), incoming.getMetadata().getId());
+      assertEquals(md.getCreationTime(), incoming.getMetadata().getCreationTime());
+      assertEquals(md.isNew(), incoming.getMetadata().isNew());
+      assertEquals(md.isValid(), incoming.getMetadata().isValid());
+      assertEquals(md.getMaxInactiveInterval(), incoming.getMetadata().getMaxInactiveInterval());
+      assertTrue(incoming.providesSessionAttributes());
+      assertEquals(attrs, incoming.getSessionAttributes());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#getSessionTimestamp(java.lang.String)}.
+    */
+   public void testGetSessionTimestamp()
+   {
+      testee.start();
+      String id = nextId();
+      
+      assertNull(testee.getSessionTimestamp(id));
+      
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(1, incoming.getVersion());
+      assertEquals(ts.longValue(), incoming.getTimestamp());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#getSessionVersion(java.lang.String)}.
+    */
+   public void testGetSessionVersion()
+   {
+      testee.start();
+      String id = nextId();
+      
+      assertNull(testee.getSessionVersion(id));
+      
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(30000);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 1, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      IncomingDistributableSessionData incoming = testee.getSessionData(id, true);
+      assertEquals(1, incoming.getVersion());
+   }
+
+   /**
+    * Test method for {@link org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase#processExpires()}.
+    */
+   public void testProcessExpires()
+   {
+      testee.setCleanupInterval(2);
+      testee.start();
+      
+      int existing = testee.getSize();
+      
+      DistributableSessionMetadata md = new DistributableSessionMetadata();
+      String id = nextId();
+      md.setId(id + ".full");
+      md.setCreationTime(System.currentTimeMillis());
+      md.setNew(true);
+      md.setValid(true);
+      md.setMaxInactiveInterval(1);
+      Long ts = Long.valueOf(md.getCreationTime() + 1); 
+      Map<String, Object> attrs = new HashMap<String, Object>();
+      attrs.put("key", "value");
+      OutgoingSessionGranularitySessionData sessionData = new MockOutgoingSessionData(id, 0, ts, md, attrs);
+      testee.storeSessionData(sessionData);
+      
+      sleep(500);
+      
+      testee.processExpires();
+      
+      assertEquals(Integer.valueOf(0), testee.getSessionVersion(id));
+      
+      sleep(2001);
+      
+      testee.processExpires();
+      
+      assertNull(testee.getSessionVersion(id));
+      
+      assertEquals(existing, testee.getSize());
+   }
+
+   private void sleep(int sleeptime)
+   {
+      try
+      {
+         Thread.sleep(sleeptime);
+      }
+      catch (InterruptedException ignored)
+      {
+         ;
+      }
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/DriverManagerPersistentStoreUnitTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMaxUnreplicatedIntervalTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMaxUnreplicatedIntervalTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMaxUnreplicatedIntervalTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,340 @@
+/*
+ * 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.logging.Logger;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.test.cluster.web.CacheHelper;
+import org.jboss.test.cluster.web.mocks.BasicRequestHandler;
+import org.jboss.test.cluster.web.mocks.MutableObject;
+import org.jboss.test.cluster.web.mocks.SetAttributesRequestHandler;
+import org.jboss.test.cluster.web.persistent.PersistentSessionTestUtil;
+import org.jboss.test.cluster.web.persistent.SimplePersistentStoreTestSetup;
+import org.jboss.web.tomcat.service.session.persistent.DataSourcePersistentManager;
+
+/**
+ * Tests of handling of ClusteredSession.maxUnreplicatedInterval.  This base
+ * test is run with SESSION granularity.
+ * 
+ * @author Brian Stansberry
+ */
+public class PersistentStoreMaxUnreplicatedIntervalTestCase extends JBossTestCase
+{
+   protected static long testId = System.currentTimeMillis();
+   
+   protected Logger log = Logger.getLogger(getClass());   
+   
+   protected Set<DataSourcePersistentManager> managers = new HashSet<DataSourcePersistentManager>();
+   
+   protected Map<String, Object> allAttributes;
+   protected Map<String, Object> immutables;
+   protected Map<String, Object> mutables;
+   
+   public PersistentStoreMaxUnreplicatedIntervalTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      return SimplePersistentStoreTestSetup.getDeploySetup(PersistentStoreMaxUnreplicatedIntervalTestCase.class);
+   }
+
+   
+   @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 (DataSourcePersistentManager manager : managers)      
+         manager.stop();
+      
+      managers.clear();
+   }
+   
+   protected ReplicationGranularity getReplicationGranularity()
+   {
+      return ReplicationGranularity.SESSION;
+   }
+   
+   protected ReplicationTrigger getReplicationTrigger()
+   {
+      return ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET;
+   }
+   
+   /**
+    * Tests that a maxUnreplicatedInterval of 1 second prevents inadvertent
+    * session expiration. Test makes a read-only request after the 
+    * maxUnreplicatedInterval has passed, waits long enough for the session
+    * to expire on the remote node if the read-only request didn't trigger a 
+    * timestamp replication, and then accesses the session on the 2nd node to
+    * confirm that the session is still alive.
+    * 
+    * @throws Exception
+    */
+   public void testBasicMaxIntervalPreventsExpiration() throws Exception
+   {
+      log.info("++++ Starting testBasicMaxIntervalPreventsExpiration ++++");
+      
+      maxIntervalPreventsExpirationTest(false);
+   }
+   
+   /**
+    * Tests that the override maxUnreplicatedInterval of 0 prevents inadvertent
+    * session expiration. Test makes a read-only request after one second 
+    * has passed, waits long enough for the session
+    * to expire on the remote node if the read-only request didn't trigger a 
+    * timestamp replication, and then accesses the session on the 2nd node to
+    * confirm that the session is still alive.
+    * 
+    * @throws Exception
+    */
+   public void testZeroMaxIntervalPreventsExpiration() throws Exception
+   {
+      log.info("++++ Starting testZeroMaxIntervalPreventsExpiration ++++");
+      
+      maxIntervalPreventsExpirationTest(true);
+   }
+   
+   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
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 3, maxUnrep);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      // Establish session.
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(mgr0, 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(mgr0, 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(mgr1, getHandler, setHandler.getSessionId());
+      
+      validateExpectedAttributes(allAttributes, getHandler);
+   }
+   
+   /**
+    * Tests that setting a maxUnreplicatedInterval of 1 second prevents
+    * timestamp replication during read-only requests during that one second. 
+    * Test makes a read-only request during the 1 second maxUnreplicatedInterval,
+    * which should prevent timestamp replication. Test then waits long enough
+    * for the session to be considered expired on the remote node only if the
+    * timestamp wasn't replicated. Test fails over to remote node and confirms
+    * that the session was expired.
+    * 
+    * @throws Exception
+    */
+   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
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 3, 1);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+      SessionTestUtil.invokeRequest(mgr0, 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(mgr0, 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(mgr1, 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.
+    * 
+    * COMMENTED OUT BECAUSE the whole idea doesn't work. The mgr1 that isn't
+    * aware of the mgr0 activity does an outdated check against db and finds
+    * out
+    * 
+    * @throws Exception
+    */
+//   public void testRemoteExpirationGracePeriod() throws Exception
+//   {
+//      log.info("++++ Starting testRemoteExpirationGracePeriod ++++");
+//      
+//      String warname = String.valueOf(++testId);
+//      
+//      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 3, 2);
+//      DataSourcePersistentManager mgr0 = mgrs[0];
+//      DataSourcePersistentManager mgr1 = mgrs[1];
+//      
+//      // Establish a session on mgr1
+//      BasicRequestHandler getHandler = new BasicRequestHandler(immutables.keySet(), false);
+//      SessionTestUtil.invokeRequest(mgr1, getHandler, null);
+//      
+//      String session1Id = getHandler.getSessionId();
+//      
+//      getHandler = new BasicRequestHandler(immutables.keySet(), false);
+//      SessionTestUtil.invokeRequest(mgr1, getHandler, null);
+//      
+//      String session2Id = getHandler.getSessionId();
+//      
+//      // Modify on mgr0
+//      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(allAttributes, false);
+//      SessionTestUtil.invokeRequest(mgr0, setHandler, session1Id);
+//      setHandler = new SetAttributesRequestHandler(allAttributes, false);
+//      SessionTestUtil.invokeRequest(mgr0, setHandler, session2Id);
+//      
+//      // Sanity check of the DB
+//      assertNotNull(PersistentSessionTestUtil.getSessionVersion(PersistentSessionTestUtil.getDataSource(), session1Id, mgr0.getContainer().getName()));
+//      assertNotNull(PersistentSessionTestUtil.getSessionVersion(PersistentSessionTestUtil.getDataSource(), session2Id, mgr0.getContainer().getName()));
+//      
+//      // Overage the session
+//      Thread.sleep(3010);
+//      // Try to force out the overaged session
+//      mgr1.backgroundProcess();
+//      // Confirm they are still there
+//      assertNotNull(PersistentSessionTestUtil.getSessionVersion(PersistentSessionTestUtil.getDataSource(), session1Id, mgr0.getContainer().getName()));
+//      assertNotNull(PersistentSessionTestUtil.getSessionVersion(PersistentSessionTestUtil.getDataSource(), session2Id, mgr0.getContainer().getName()));
+//       
+//      // Access one to prove it gets expired once the manager can see its real timestamp
+//      getHandler = new BasicRequestHandler(allAttributes.keySet(), false);
+//      SessionTestUtil.invokeRequest(mgr1, getHandler, session1Id);      
+//      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
+//      mgr1.backgroundProcess();
+//      assertNull(PersistentSessionTestUtil.getSessionVersion(PersistentSessionTestUtil.getDataSource(), session2Id, mgr0.getContainer().getName()));
+//   }
+   
+   protected DataSourcePersistentManager[] getCacheManagers(String warname, int maxInactive, int maxUnreplicated)
+      throws Exception
+   {
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager(warname, maxInactive, null);
+      PersistentSessionTestUtil.configureManager(mgr0, getReplicationGranularity(), getReplicationTrigger(), true, maxUnreplicated);
+      this.managers.add(mgr0);
+      mgr0.start();
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager(warname, maxInactive, null);
+      PersistentSessionTestUtil.configureManager(mgr1, getReplicationGranularity(), getReplicationTrigger(), true, maxUnreplicated);
+      this.managers.add(mgr1);
+      mgr1.start();
+      
+      return new DataSourcePersistentManager[]{mgr0, mgr1};
+   }
+   
+   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());
+   }
+   
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMaxUnreplicatedIntervalTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMemoryLeakTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMemoryLeakTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMemoryLeakTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,476 @@
+/*
+ * 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.io.ObjectStreamException;
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import junit.framework.Test;
+
+import org.apache.catalina.Session;
+import org.jboss.cache.pojo.PojoCache;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.test.cluster.web.mocks.BasicRequestHandler;
+import org.jboss.test.cluster.web.mocks.InvalidateSessionRequestHandler;
+import org.jboss.test.cluster.web.mocks.RemoveAttributesRequestHandler;
+import org.jboss.test.cluster.web.mocks.SetAttributesRequestHandler;
+import org.jboss.test.cluster.web.notification.SessionSpecListenerAttribute;
+import org.jboss.test.cluster.web.persistent.PersistentSessionTestUtil;
+import org.jboss.test.cluster.web.persistent.SimplePersistentStoreTestSetup;
+import org.jboss.web.tomcat.service.session.persistent.DataSourcePersistentManager;
+
+/**
+ * Tests that references to cached sessions and attributes are released. 
+ * 
+ * @author Brian Stansberry
+ */
+public class PersistentStoreMemoryLeakTestCase extends JBossTestCase
+{
+   protected static PojoCache[] pojoCaches = new PojoCache[2];
+
+   protected static long testId = System.currentTimeMillis();
+   
+   public static final String KEY = "Key";
+   public static final Set<String> KEYS = new HashSet<String>();
+   static
+   {
+      KEYS.add(KEY);
+   }
+   
+   protected Logger log = Logger.getLogger(getClass());   
+   
+   protected Set<DataSourcePersistentManager> managers = new HashSet<DataSourcePersistentManager>();
+   
+   public PersistentStoreMemoryLeakTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      return SimplePersistentStoreTestSetup.getDeploySetup(PersistentStoreMemoryLeakTestCase.class);
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      cleanHeap();
+      
+      super.tearDown();
+      
+      for (DataSourcePersistentManager manager : managers)    
+      {
+         try
+         {
+            manager.stop();
+         }
+         catch (RuntimeException ignored)
+         {
+            log.debug("tearDown(): Caught exception cleaning up manager -- " + ignored.getLocalizedMessage()); 
+         }
+      }
+      managers.clear();
+      
+      SessionSpecListenerAttribute.invocations.clear();
+      
+      Attribute.clear();
+      System.gc();
+   }
+   
+   protected ReplicationGranularity getReplicationGranularity()
+   {
+      return ReplicationGranularity.SESSION;
+   }
+   
+   protected ReplicationTrigger getReplicationTrigger()
+   {
+      return ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET;
+   }
+   
+   public void testSessionLifecycle() throws Exception
+   {
+      log.info("++++ Starting testSessionLifecycle ++++");
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 30 mins maxUnreplicated of 0
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 1800, 1);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      
+      // Initial request
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(getAttributeMap(), false);
+      log.info("initial request");
+      SessionTestUtil.invokeRequest(mgr0, setHandler, null);      
+      
+      String sessionId = setHandler.getSessionId();
+      WeakReference<Session> session0A = new WeakReference<Session>(mgr0.findSession(sessionId));      
+      SessionTestUtil.cleanupPipeline(mgr0);
+      assertNotNull(session0A.get());
+      
+      // Modify attribute request
+      setHandler = new SetAttributesRequestHandler(getAttributeMap(), false);
+      log.info("Modify attribute request");
+      SessionTestUtil.invokeRequest(mgr0, setHandler, sessionId);      
+      SessionTestUtil.cleanupPipeline(mgr0);
+      
+      cleanHeap();
+      assertAttributeCount(1);
+      
+      // Passivate
+      Thread.sleep(1100);
+      
+      log.info("passivate node 0");
+      mgr0.backgroundProcess();
+      log.info("passivate node 1");
+      mgr1.backgroundProcess();
+      
+      cleanHeap();
+      assertAttributeCount(0);
+      assertNullReference(session0A);
+      
+      // Remove attribute request
+      RemoveAttributesRequestHandler removeHandler = new RemoveAttributesRequestHandler(KEYS, false);
+      log.info("remove request");
+      SessionTestUtil.invokeRequest(mgr0, removeHandler, sessionId);
+      
+      WeakReference<Session> session0B = new WeakReference<Session>(mgr0.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr0);
+      cleanHeap();
+      assertAttributeCount(0);
+      assertNotNull(session0B.get());
+      
+      // Failover request
+      setHandler = new SetAttributesRequestHandler(getAttributeMap(), false);
+      log.info("failover request");
+      SessionTestUtil.invokeRequest(mgr1, setHandler, sessionId);
+      
+      WeakReference<Session> session1A = new WeakReference<Session>(mgr1.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr1);
+      assertNotNull(session1A.get());
+      assertAttributeCount(1);
+      
+      // Passivate
+      Thread.sleep(1100);
+      
+      log.info("passivate node 0");
+      mgr0.backgroundProcess();
+      log.info("passivate node 1");
+      mgr1.backgroundProcess();
+      
+      cleanHeap();
+      assertAttributeCount(0);
+      assertNullReference(session0B);
+      assertNullReference(session1A);
+      
+      // Reactivate
+      BasicRequestHandler getHandler = new BasicRequestHandler(KEYS, false);
+      log.info("activate node 1");
+      SessionTestUtil.invokeRequest(mgr1, getHandler, sessionId);
+      
+      WeakReference<Session> session1B = new WeakReference<Session>(mgr1.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr1);
+      assertNotNull(session1B.get());
+      assertAttributeCount(1);      
+      
+      // Fail back 
+      getHandler = new BasicRequestHandler(KEYS, false);
+      log.info("fail back request");
+      SessionTestUtil.invokeRequest(mgr0, getHandler, sessionId);
+      
+      WeakReference<Session> session0C = new WeakReference<Session>(mgr0.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr0);
+      assertNotNull(session0C.get());
+      assertAttributeCount(2);   
+      
+      // Invalidate session
+      InvalidateSessionRequestHandler invalidateHandler = new InvalidateSessionRequestHandler(KEYS, false);
+      log.info("invalidate request");
+      SessionTestUtil.invokeRequest(mgr0, invalidateHandler, sessionId);
+      SessionTestUtil.cleanupPipeline(mgr0);
+      
+      cleanHeap();
+      assertNotNull(session1B.get());
+      assertNullReference(session0C);
+      assertAttributeCount(1);
+      
+      // Make mgr1 aware of the invalidation
+      getHandler = new BasicRequestHandler(KEYS, false);
+      SessionTestUtil.invokeRequest(mgr1, getHandler, sessionId);
+      
+      cleanHeap();
+      assertNullReference(session1B);
+      assertAttributeCount(0);
+   }
+   
+   public void testSessionExpiration() throws Exception
+   {
+      log.info("++++ Starting testSessionExpiration ++++");
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 2 secs and a maxIdle of 10 (don't passivate)
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 2, 10);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      // Initial request
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(getAttributeMap(), false);
+      log.info("initial request");
+      SessionTestUtil.invokeRequest(mgr0, setHandler, null);
+      assertAttributeCount(1);        
+      
+      String sessionId = setHandler.getSessionId();
+      WeakReference<Session> session0A = new WeakReference<Session>(mgr0.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr0);
+      assertNotNull(session0A.get());
+      assertAttributeCount(1);        
+      
+      // Failover request
+      setHandler = new SetAttributesRequestHandler(getAttributeMap(), false);
+      log.info("fail over request");
+      SessionTestUtil.invokeRequest(mgr1, setHandler, sessionId);
+      assertNotNull(setHandler.getCheckedAttributes().get(KEY));
+      assertEquals(Attribute.COUNT -1, ((Attribute) setHandler.getCheckedAttributes().get(KEY)).getCount());
+      
+      WeakReference<Session> session1A = new WeakReference<Session>(mgr1.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr1);
+      
+      cleanHeap();
+      assertNotNull(session1A.get());
+      assertAttributeCount(2);
+      
+      // Expire
+      Thread.sleep(2100);
+      
+      log.info("expire node 0");
+      mgr0.backgroundProcess();
+      log.info("expire node 1");
+      mgr1.backgroundProcess();
+      
+      cleanHeap();
+      assertNullReference(session0A);
+      assertNullReference(session1A);
+      assertAttributeCount(0);
+   }
+
+   private void cleanHeap()
+   {
+      System.gc(); 
+      System.runFinalization();
+      System.gc(); 
+      System.runFinalization();
+      System.gc();
+      log.debug("Heap cleaned");
+   }
+   
+   private void assertNullReference(WeakReference<?> ref)
+   {
+      long limit = System.currentTimeMillis() + 2500;
+      while (ref.get() != null && System.currentTimeMillis() < limit)
+      {
+         cleanHeap();
+         if (ref.get() != null)
+         {
+            try
+            {
+               Thread.sleep(50);
+            }
+            catch (InterruptedException e)
+            {
+               Thread.currentThread().interrupt();
+               log.warn("interrupted");
+               break;
+            }
+         }
+      }
+      assertNull(ref.get());
+   }
+   
+   private void assertAttributeCount(int expected)
+   {
+      long limit = System.currentTimeMillis() + 2500;
+      while (Attribute.attributeCount() > expected && System.currentTimeMillis() < limit)
+      {
+         cleanHeap();
+         if (Attribute.attributeCount() > expected)
+         {
+            try
+            {
+               Thread.sleep(50);
+            }
+            catch (InterruptedException e)
+            {
+               Thread.currentThread().interrupt();
+               log.warn("interrupted");
+               break;
+            }
+         }
+      }
+      assertEquals(expected, Attribute.attributeCount());
+   }
+   
+   public void testUndeploy() throws Exception
+   {
+      log.info("++++ Starting testUndeploy ++++");
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 30 mins and no maxIdle
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 1800, -1);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      // Initial request
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(getAttributeMap(), false);
+      SessionTestUtil.invokeRequest(mgr0, setHandler, null); 
+      assertAttributeCount(1);  
+      
+      String sessionId = setHandler.getSessionId();
+      WeakReference<Session> session0A = new WeakReference<Session>(mgr0.findSession(sessionId));
+      SessionTestUtil.cleanupPipeline(mgr0);
+      assertNotNull(session0A.get());
+      
+      mgr0.stop();         
+      mgr1.stop();    
+      
+      cleanHeap();
+      assertNull(session0A.get());
+      assertAttributeCount(0);
+   }
+   
+   protected DataSourcePersistentManager[] getCacheManagers(String warname, int maxInactive, int maxIdle)
+      throws Exception
+   {
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager(warname, maxInactive, null);
+      PersistentSessionTestUtil.configureManager(mgr0, getReplicationGranularity(), getReplicationTrigger(), -1, maxIdle > 0, maxIdle, -1 ,false, 0);
+      this.managers.add(mgr0);
+      mgr0.start();
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager(warname, maxInactive, null);
+      PersistentSessionTestUtil.configureManager(mgr1, getReplicationGranularity(), getReplicationTrigger(), -1, true, maxIdle, -1 ,false, 0);
+      this.managers.add(mgr1);
+      mgr1.start();
+      
+      return new DataSourcePersistentManager[]{mgr0, mgr1};
+   }
+   
+   private static Map<String, Object> getAttributeMap()
+   {
+      Object val = Attribute.newAttribute();
+      return Collections.singletonMap(KEY, val);
+   }
+   
+   /** Class that keeps track of all its instances */
+   private static class Attribute implements Serializable
+   {
+      /** The serialVersionUID */
+      private static final long serialVersionUID = 1L;
+      
+      private static final Logger log = Logger.getLogger(Attribute.class);
+      
+      public static int COUNT = 0;
+      
+      private static final WeakHashMap<Attribute, String> attributes = new WeakHashMap<Attribute, String>();
+      
+      private final int count;
+      
+      static Attribute newAttribute()
+      {
+         log.info("Attribute: new Attribute");
+         return getAttribute(++COUNT);
+      }      
+      
+      private static Attribute getAttribute(int count)
+      {
+         Attribute a = new Attribute(count);
+         attributes.put(a,  "value");
+         log.info("Stored ref to Attribute@" + System.identityHashCode(a));
+         return a;
+      }
+      
+      private static void clear()
+      {
+         attributes.clear();
+      }
+      
+      private Attribute(int count)
+      {
+         this.count = count;
+      }
+      
+      static int attributeCount()
+      {
+         return attributes.size();
+      }
+
+      public int getCount()
+      {
+         return count;
+      }
+      
+      private Object writeReplace() throws ObjectStreamException
+      {
+         log.info("Attribute: serialized");
+         return new SerializedForm(count);
+      }
+      
+      private static class SerializedForm implements Serializable
+      {
+         /** The serialVersionUID */
+         private static final long serialVersionUID = 1L;
+         
+         private final int count;
+         
+         private SerializedForm(int count)
+         {
+            this.count = count;
+         }
+         
+         private Object readResolve() throws ObjectStreamException
+         {
+            log.info("Attribute: deserialized");
+            return getAttribute(count);
+         }
+      }
+
+      @Override
+      protected void finalize() throws Throwable
+      {
+         log.info("Attribute@" + System.identityHashCode(this) + " finalized");
+         super.finalize();
+      }
+      
+      
+
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreMemoryLeakTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionCountUnitTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionCountUnitTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionCountUnitTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,631 @@
+/*
+ * 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.test.cluster.defaultcfg.simpleweb.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import org.apache.catalina.Manager;
+import org.apache.catalina.Session;
+import org.jboss.logging.Logger;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.test.cluster.web.persistent.PersistentSessionTestUtil;
+import org.jboss.test.cluster.web.persistent.SimplePersistentStoreTestSetup;
+import org.jboss.web.tomcat.service.session.persistent.DataSourcePersistentManager;
+
+/**
+ * Unit tests of session count management with a persistent manager.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 85945 $
+ */
+public class PersistentStoreSessionCountUnitTestCase extends TestCase
+{
+   private static final Logger log = Logger.getLogger(PersistentStoreSessionCountUnitTestCase.class);
+   
+   private static long testCount = System.currentTimeMillis();
+   
+   /**
+    * Create a new SessionCountUnitTestCase.
+    * 
+    * @param name
+    */
+   public PersistentStoreSessionCountUnitTestCase(String name)
+   {
+      super(name);
+   } 
+
+   public static Test suite() throws Exception
+   {
+      return SimplePersistentStoreTestSetup.getDeploySetup(PersistentStoreSessionCountUnitTestCase.class);
+   }
+
+   public void testStandaloneMaxSessions() throws Exception
+   {
+      log.info("Enter testStandaloneMaxSessions");
+      
+      ++testCount;
+      
+      DataSourcePersistentManager mgr = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);       
+      PersistentSessionTestUtil.configureManager(mgr, 2);
+      
+      mgr.start();
+      
+      assertFalse("Passivation is disabled", mgr.isPassivationEnabled());
+      assertEquals("Correct max active count", 2, mgr.getMaxActiveAllowed());
+      
+      // Set up a session
+      Session sess1 = createAndUseSession(mgr, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      
+      createAndUseSession(mgr, "2", true, true);
+      
+      assertEquals("Session count correct", 2, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 2, mgr.getLocalActiveSessionCount());
+      
+      // Should fail to create a 3rd
+      createAndUseSession(mgr, "3", false, false);
+      
+      // Confirm a session timeout clears space
+      sess1.setMaxInactiveInterval(1);       
+      SessionTestUtil.sleepThread(1100);      
+      
+      createAndUseSession(mgr, "3", true, true);      
+      
+      assertEquals("Session count correct", 2, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 2, mgr.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 3, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr.getExpiredSessionCount());
+   }
+   
+   public void testStandaloneMaxSessionsWithMaxIdle()
+         throws Exception
+   {
+      log.info("Enter testStandaloneMaxSessionsWithMaxIdle");
+      
+      ++testCount;
+      DataSourcePersistentManager mgr = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);
+       
+      PersistentSessionTestUtil.configureManager(mgr, 1, true, 1, -1);
+      
+      mgr.start();
+      
+      assertTrue("Passivation is enabled", mgr.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 1, mgr.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", -1, mgr.getPassivationMinIdleTime());
+
+      // Set up a session
+      Session sess1 = createAndUseSession(mgr, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      
+      // Should fail to create a 2nd
+      createAndUseSession(mgr, "2", false, false);
+      
+      // Confirm a session timeout clears space
+      sess1.setMaxInactiveInterval(1);       
+      SessionTestUtil.sleepThread(1100);      
+      
+      createAndUseSession(mgr, "2", true, true);      
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 2, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr.getPassivatedSessionCount());
+
+      //    Sleep past maxIdleTime
+      SessionTestUtil.sleepThread(1100);        
+      
+      assertEquals("Passivated session count correct", 0, mgr.getPassivatedSessionCount());
+      
+      createAndUseSession(mgr, "3", true, true);      
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 3, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 1, mgr.getPassivatedSessionCount());
+      
+   }
+   
+   public void testStandaloneMaxSessionsWithMinIdle() throws Exception
+   {
+      log.info("Enter testStandaloneMaxSessionsWithMinIdle");
+      
+      ++testCount;
+      DataSourcePersistentManager mgr = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);
+      
+      PersistentSessionTestUtil.configureManager(mgr, 1, true, 3, 1);
+      
+      mgr.start();
+      
+      assertTrue("Passivation is enabled", mgr.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 3, mgr.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr.getPassivationMinIdleTime());
+      
+      // Set up a session
+      Session sess1 = createAndUseSession(mgr, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      
+      // Should fail to create a 2nd
+      createAndUseSession(mgr, "2", false, false);
+      
+      // Confirm a session timeout clears space
+      sess1.setMaxInactiveInterval(1);       
+      SessionTestUtil.sleepThread(1100);      
+      
+      createAndUseSession(mgr, "2", true, false);      
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());     
+      assertEquals("Created session count correct", 2, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr.getExpiredSessionCount());
+
+      //    Sleep past minIdleTime
+      SessionTestUtil.sleepThread(1100);        
+      
+//      assertTrue("Session 2 still valid", sess2.isValid());
+      assertEquals("Passivated session count correct", 0, mgr.getPassivatedSessionCount());
+      
+      createAndUseSession(mgr, "3", true, true);      
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 3, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 1, mgr.getPassivatedSessionCount());
+   }
+   
+   public void testReplicatedMaxSessions() throws Exception
+   {
+      log.info("Enter testReplicatedMaxSessions");
+      
+      ++testCount;
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager("test" + testCount, 1, null);      
+      PersistentSessionTestUtil.configureManager(mgr0, 1);
+      
+      mgr0.start();
+      
+      assertFalse("Passivation is disabled", mgr0.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr0.getMaxActiveAllowed());
+      assertEquals("Correct max inactive interval", 1, mgr0.getMaxInactiveInterval());
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager("test" + testCount, 1, null);
+      PersistentSessionTestUtil.configureManager(mgr1, 1);
+      
+      mgr1.start();
+      
+      assertFalse("Passivation is disabled", mgr1.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr1.getMaxActiveAllowed());
+      assertEquals("Correct max inactive interval", 1, mgr1.getMaxInactiveInterval());
+      
+      // Set up a session
+      createAndUseSession(mgr0, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());      
+      assertEquals("Session count correct", 0, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 0, mgr1.getLocalActiveSessionCount());
+      
+      // Get it in-memory on mgr1 as well 
+      Session sess1 = useSession(mgr1, "1");
+      
+      // A 2nd session should fail
+      createAndUseSession(mgr0, "2", false, false);
+      createAndUseSession(mgr1, "2", false, false);
+      
+      // Confirm a session timeout clears space
+      sess1.setMaxInactiveInterval(1);      
+      useSession(mgr1, "1");   
+      useSession(mgr0, "1"); 
+      SessionTestUtil.sleepThread(mgr0.getMaxInactiveInterval() * 1000 + 100);      
+      
+      createAndUseSession(mgr0, "2", true, true); 
+      createAndUseSession(mgr1, "3", true, true);      
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 2, mgr0.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr0.getExpiredSessionCount());      
+      
+      assertEquals("Session count correct", 1, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr1.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 1, mgr1.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 1, mgr1.getExpiredSessionCount());
+   }
+   
+   public void testReplicatedMaxSessionsWithMaxIdle() throws Exception
+   {
+      log.info("Enter testReplicatedMaxSessionsWithMaxIdle");
+      
+      ++testCount;
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);      
+      PersistentSessionTestUtil.configureManager(mgr0, 1, true, 1, -1);
+      
+      mgr0.start();
+      
+      assertTrue("Passivation is enabled", mgr0.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr0.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 1, mgr0.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", -1, mgr0.getPassivationMinIdleTime());
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);
+      PersistentSessionTestUtil.configureManager(mgr1, 1, true, 1, -1);
+      
+      mgr1.start();
+      
+      assertTrue("Passivation is enabled", mgr1.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr1.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 1, mgr1.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", -1, mgr1.getPassivationMinIdleTime());
+      
+      // Set up a session
+      createAndUseSession(mgr0, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr0.getPassivatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr0.getExpiredSessionCount());       
+      assertEquals("Session count correct", 0, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 0, mgr1.getLocalActiveSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr1.getPassivatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr1.getExpiredSessionCount()); 
+      
+      // Get it in-memory on mgr1 as well 
+      useSession(mgr1, "1");
+      
+      // A 2nd session should fail
+      createAndUseSession(mgr0, "2", false, false);
+      createAndUseSession(mgr1, "2", false, false);
+      
+      //    Sleep past maxIdleTime      
+      SessionTestUtil.sleepThread(1100);        
+      
+      assertEquals("Passivated session count correct", 0, mgr1.getPassivatedSessionCount());
+       
+      createAndUseSession(mgr1, "2", true, true); 
+      createAndUseSession(mgr0, "3", true, true); 
+       
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 2, mgr0.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr0.getExpiredSessionCount());  
+      assertEquals("Passivated session count correct", 1, mgr0.getPassivatedSessionCount());    
+       
+      assertEquals("Session count correct", 1, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr1.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 1, mgr1.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr1.getExpiredSessionCount()); 
+      assertEquals("Passivated session count correct", 1, mgr1.getPassivatedSessionCount());     
+   }
+   
+   public void testReplicatedMaxSessionsWithMinIdle() throws Exception
+   {
+      log.info("Enter testReplicatedMaxSessionsWithMinIdle");
+      
+      ++testCount;
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);
+      PersistentSessionTestUtil.configureManager(mgr0, 1, true, 3, 1);
+      
+      mgr0.start();
+      
+      assertTrue("Passivation is enabled", mgr0.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr0.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 3, mgr0.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr0.getPassivationMinIdleTime());
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);
+      PersistentSessionTestUtil.configureManager(mgr1, 1, true, 3, 1);
+      
+      mgr1.start();
+      
+      assertTrue("Passivation is enabled", mgr1.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr1.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 3, mgr1.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr1.getPassivationMinIdleTime());
+      
+      // Set up a session
+      createAndUseSession(mgr0, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr0.getPassivatedSessionCount());      
+      assertEquals("Session count correct", 0, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 0, mgr1.getLocalActiveSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr0.getPassivatedSessionCount());
+      
+      // Get it in-memory on mgr1 as well 
+      useSession(mgr1, "1");
+      
+      // A 2nd session should fail
+      createAndUseSession(mgr0, "2", false, false);
+      createAndUseSession(mgr1, "2", false, false);
+      
+      // Sleep past minIdleTime      
+      SessionTestUtil.sleepThread(1100);        
+      
+      assertEquals("Passivated session count correct", 0, mgr1.getPassivatedSessionCount());
+       
+      createAndUseSession(mgr1, "2", true, true);   
+      createAndUseSession(mgr0, "3", true, true);    
+       
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 2, mgr0.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr0.getExpiredSessionCount());  
+      assertEquals("Passivated session count correct", 1, mgr0.getPassivatedSessionCount());    
+       
+      assertEquals("Session count correct", 1, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr1.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 1, mgr1.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr1.getExpiredSessionCount()); 
+      assertEquals("Passivated session count correct", 1, mgr1.getPassivatedSessionCount());     
+      
+   }
+   
+   public void testStandaloneRedeploy() throws Exception
+   {
+      log.info("Enter testStandaloneRedeploy");
+      ++testCount;
+      DataSourcePersistentManager mgr = PersistentSessionTestUtil.createManager("test" + testCount, 300, null);      
+      PersistentSessionTestUtil.configureManager(mgr, 2, true, 3, 1);
+      
+      mgr.start();
+      
+      assertTrue("Passivation is enabled", mgr.isPassivationEnabled());
+      assertEquals("Correct max active count", 2, mgr.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 3, mgr.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr.getPassivationMinIdleTime());
+      
+      // Set up a session
+      createAndUseSession(mgr, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr.getLocalActiveSessionCount());
+      
+      // And a 2nd
+      createAndUseSession(mgr, "2", true, true);     
+      
+      assertEquals("Session count correct", 2, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 2, mgr.getLocalActiveSessionCount());     
+      assertEquals("Created session count correct", 2, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr.getExpiredSessionCount());
+
+      //    Sleep past minIdleTime
+      SessionTestUtil.sleepThread(1100);
+      
+      assertEquals("Passivated session count correct", 0, mgr.getPassivatedSessionCount());
+      
+      createAndUseSession(mgr, "3", true, true);      
+      
+      assertEquals("Session count correct", 2, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 2, mgr.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 3, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 1, mgr.getPassivatedSessionCount());
+      
+      mgr.stop();
+      
+      mgr = PersistentSessionTestUtil.createManager("test" + testCount, 5, null);      
+      PersistentSessionTestUtil.configureManager(mgr, 2, true, 3, 1);
+      
+      mgr.start();
+      
+      assertTrue("Passivation is enabled", mgr.isPassivationEnabled());
+      assertEquals("Correct max active count", 2, mgr.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 3, mgr.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr.getPassivationMinIdleTime());     
+      
+      assertEquals("Session count correct", 0, mgr.getActiveSessionCount());
+      assertEquals("Local session count correct", 0, mgr.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 0, mgr.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr.getPassivatedSessionCount());
+      
+      // Sleep past minIdleTime
+      SessionTestUtil.sleepThread(1100);
+      
+      createAndUseSession(mgr, "4", true, true); 
+   }
+   
+   public void testReplicatedRedeploy() throws Exception
+   {
+      log.info("Enter testReplicatedRedeploy");
+      
+      replicatedWarRedeployTest(false);
+   }
+   
+   public void testReplicatedRestart() throws Exception
+   {
+      log.info("Enter testReplicatedRestart");
+      
+      replicatedWarRedeployTest(true);
+      
+   }
+   
+   private void replicatedWarRedeployTest(boolean fullRestart)
+         throws Exception
+   {
+      ++testCount;
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager("test" + testCount, 300, null);
+      PersistentSessionTestUtil.configureManager(mgr0, 1, true, 30, 1);
+      
+      mgr0.start();
+      
+      assertTrue("Passivation is enabled", mgr0.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr0.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 30, mgr0.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr0.getPassivationMinIdleTime());
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager("test" + testCount, 300, null);
+      PersistentSessionTestUtil.configureManager(mgr1, 1, true, 30, 1);
+      
+      mgr1.start();
+      
+      assertTrue("Passivation is enabled", mgr1.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr1.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 30, mgr1.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr1.getPassivationMinIdleTime());
+      
+      // Set up a session
+      createAndUseSession(mgr0, "1", true, true);
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());    
+      assertEquals("Session count correct", 0, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 0, mgr1.getLocalActiveSessionCount());
+      
+      // Create a 2nd
+      createAndUseSession(mgr1, "2", true, true);     
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());     
+      assertEquals("Created session count correct", 1, mgr0.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr0.getExpiredSessionCount());
+      assertEquals("Session count correct", 1, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr1.getLocalActiveSessionCount());     
+      assertEquals("Created session count correct", 1, mgr1.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr1.getExpiredSessionCount());
+
+      //    Sleep past minIdleTime
+      SessionTestUtil.sleepThread(1100);
+      
+      assertEquals("Passivated session count correct", 0, mgr1.getPassivatedSessionCount());
+      
+      createAndUseSession(mgr1, "3", true, true);      
+      
+      assertEquals("Session count correct", 1, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr0.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 1, mgr0.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr0.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 0, mgr0.getPassivatedSessionCount());
+      // mgr1 only has 1 active since it passivated one when it created #3 
+      assertEquals("Session count correct", 1, mgr1.getActiveSessionCount());
+      assertEquals("Local session count correct", 1, mgr1.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 2, mgr1.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr1.getExpiredSessionCount());
+      assertEquals("Passivated session count correct", 1, mgr1.getPassivatedSessionCount());
+      
+      if (fullRestart)
+      {
+        mgr1.stop();
+      }
+      
+      mgr0.stop();
+      
+      mgr0 = PersistentSessionTestUtil.createManager("test" + testCount, 300, null);
+      PersistentSessionTestUtil.configureManager(mgr0, 1, true, 30, 1);
+      
+      mgr0.start();
+      
+      assertTrue("Passivation is enabled", mgr0.isPassivationEnabled());
+      assertEquals("Correct max active count", 1, mgr0.getMaxActiveAllowed());
+      assertEquals("Correct max idle time", 30, mgr0.getPassivationMaxIdleTime());
+      assertEquals("Correct min idle time", 1, mgr0.getPassivationMinIdleTime());     
+      
+//      int expected = (totalReplication && marshalling && fullRestart) ? 0 : 2;
+      int expected = 2;
+      assertEquals("Session count correct", 0, mgr0.getActiveSessionCount());
+      assertEquals("Local session count correct", 0, mgr0.getLocalActiveSessionCount());
+      assertEquals("Created session count correct", 0, mgr0.getCreatedSessionCount());
+      assertEquals("Expired session count correct", 0, mgr0.getExpiredSessionCount());
+//      expected = (totalReplication && !(marshalling && fullRestart)) ? 1 : 0;
+      expected = 1;
+      assertEquals("Passivated session count correct", 0, mgr0.getPassivatedSessionCount());
+      
+      if (!fullRestart)
+      {
+         assertEquals("Session count correct", 1, mgr1.getActiveSessionCount());
+         assertEquals("Local session count correct", 1, mgr1.getLocalActiveSessionCount());
+         assertEquals("Created session count correct", 2, mgr1.getCreatedSessionCount());
+         assertEquals("Expired session count correct", 0, mgr1.getExpiredSessionCount());
+         assertEquals("Passivated session count correct", 1, mgr1.getPassivatedSessionCount());
+      }
+      // Sleep past minIdleTime
+      SessionTestUtil.sleepThread(1100);
+      
+      createAndUseSession(mgr0, "4", true, true); 
+   }
+   
+   private Session createAndUseSession(DataSourcePersistentManager dspm, String id, 
+                           boolean canCreate, boolean access)
+         throws Exception
+   {
+      //    Shift to Manager interface when we simulate Tomcat
+      Manager mgr = dspm;
+      Session sess = mgr.findSession(id);
+      assertNull("session does not exist", sess);
+      try
+      {
+         sess = mgr.createSession(id);
+         if (!canCreate)
+            fail("Could not create session" + id);
+      }
+      catch (IllegalStateException ise)
+      {
+         if (canCreate)
+         {
+            log.error("Failed to create session " + id, ise);
+            fail("Could create session " + id);
+         }
+      }
+      
+      if (access)
+      {
+         sess.access();
+         sess.getSession().setAttribute("test", "test");
+         
+         dspm.storeSession(sess);
+         
+         sess.endAccess();
+      }
+      
+      return sess;
+   }
+   
+   private Session useSession(DataSourcePersistentManager dspm, String id)
+         throws Exception
+   {
+      //    Shift to Manager interface when we simulate Tomcat
+      Manager mgr = dspm;
+      Session sess = mgr.findSession(id);
+      assertNotNull("session exists", sess);
+      
+      sess.access();
+      sess.getSession().setAttribute("test", "test");
+      
+      dspm.storeSession(sess);
+      
+      sess.endAccess();
+      
+      return sess;
+   }
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionCountUnitTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionNotificationPolicyTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionNotificationPolicyTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionNotificationPolicyTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,701 @@
+/*
+ * 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.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.Test;
+
+import org.apache.catalina.Context;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.cluster.testutil.SessionTestUtil;
+import org.jboss.test.cluster.web.mocks.BasicRequestHandler;
+import org.jboss.test.cluster.web.mocks.InvalidateSessionRequestHandler;
+import org.jboss.test.cluster.web.mocks.RemoveAttributesRequestHandler;
+import org.jboss.test.cluster.web.mocks.SetAttributesRequestHandler;
+import org.jboss.test.cluster.web.notification.MockClusteredSessionNotificationPolicy;
+import org.jboss.test.cluster.web.notification.MockHttpSessionAttributeListener;
+import org.jboss.test.cluster.web.notification.MockHttpSessionListener;
+import org.jboss.test.cluster.web.notification.SessionSpecListenerAttribute;
+import org.jboss.test.cluster.web.persistent.PersistentSessionTestUtil;
+import org.jboss.test.cluster.web.persistent.SimplePersistentStoreTestSetup;
+import org.jboss.web.tomcat.service.session.persistent.DataSourcePersistentManager;
+
+/**
+ * Tests of handling of servlet spec notifications. 
+ * 
+ * @author Brian Stansberry
+ */
+public class PersistentStoreSessionNotificationPolicyTestCase extends JBossTestCase
+{
+   protected static long testId = System.currentTimeMillis();
+   
+   protected Logger log = Logger.getLogger(getClass());   
+   
+   protected Set<DataSourcePersistentManager> managers = new HashSet<DataSourcePersistentManager>();
+   
+   protected Map<String, Object> allAttributes;
+   protected Map<String, Object> immutables;
+   protected Map<String, Object> mutables;
+   protected Map<String, Object> attributes;
+   protected SessionSpecListenerAttribute attribute = new SessionSpecListenerAttribute();
+   protected Map<String, Object> newAttributes;
+   protected SessionSpecListenerAttribute newAttribute = new SessionSpecListenerAttribute();
+   
+   protected String origNotificationPolicy;
+   
+   public PersistentStoreSessionNotificationPolicyTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      return SimplePersistentStoreTestSetup.getDeploySetup(PersistentStoreSessionNotificationPolicyTestCase.class);
+   }
+
+   
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+      
+      origNotificationPolicy = System.getProperty("jboss.web.clustered.session.notification.policy");
+      System.setProperty("jboss.web.clustered.session.notification.policy", MockClusteredSessionNotificationPolicy.class.getName());
+      
+      attributes = new HashMap<String, Object>();
+      attributes.put("KEY", attribute);
+      attributes = Collections.unmodifiableMap(attributes);
+      
+      newAttributes = new HashMap<String, Object>();
+      newAttributes.put("KEY", newAttribute);
+      newAttributes = Collections.unmodifiableMap(newAttributes);
+   }
+
+   @Override
+   protected void tearDown() throws Exception
+   {
+      super.tearDown();
+      
+      if (origNotificationPolicy != null)
+      {
+         System.setProperty("jboss.web.clustered.session.notification.policy", origNotificationPolicy);
+      }
+      else
+      {
+         System.clearProperty("jboss.web.clustered.session.notification.policy");
+      }
+      
+      for (DataSourcePersistentManager manager : managers)    
+      {
+         try
+         {
+            manager.stop();
+         }
+         catch (RuntimeException ignored)
+         {
+            log.debug("tearDown(): Caught exception cleaning up manager -- " + ignored.getLocalizedMessage()); 
+         }
+      }
+      managers.clear();
+      
+      SessionSpecListenerAttribute.invocations.clear();
+   }
+   
+   protected ReplicationGranularity getReplicationGranularity()
+   {
+      return ReplicationGranularity.SESSION;
+   }
+   
+   protected ReplicationTrigger getReplicationTrigger()
+   {
+      return ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET;
+   }
+   
+   public void testSessionLifecycleWithNotifications() throws Exception
+   {
+      log.info("++++ Starting testSessionLifecycleWithNotifications ++++");
+      sessionLifecycleTest(true);
+   }
+   
+   public void testSessionLifecycleWithoutNotifications() throws Exception
+   {
+      log.info("++++ Starting testSessionLifecycleWithoutNotifications ++++");
+      sessionLifecycleTest(false);
+   }
+   
+   private void sessionLifecycleTest(boolean notify) throws Exception
+   {
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 30 mins maxUnreplicated of 0
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 1800, 1);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      assertTrue(mgr0.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+      MockClusteredSessionNotificationPolicy mcsnp0 = (MockClusteredSessionNotificationPolicy) mgr0.getNotificationPolicy();
+      assertNotNull("capability set", mcsnp0.getClusteredSessionNotificationCapability());
+      mcsnp0.setResponse(notify);
+      
+      assertTrue(mgr1.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+      MockClusteredSessionNotificationPolicy mcsnp1 = (MockClusteredSessionNotificationPolicy) mgr1.getNotificationPolicy();
+      assertNotNull("capability set", mcsnp1.getClusteredSessionNotificationCapability());
+      mcsnp1.setResponse(notify);
+      
+      MockHttpSessionListener hsl0 = new MockHttpSessionListener();
+      MockHttpSessionAttributeListener hsal0 = new MockHttpSessionAttributeListener();      
+      Context ctx = (Context) mgr0.getContainer();
+      ctx.setApplicationLifecycleListeners(new Object[]{ hsl0 });  
+      ctx.setApplicationEventListeners(new Object[]{ hsal0 });  
+      
+      MockHttpSessionListener hsl1 = new MockHttpSessionListener();
+      MockHttpSessionAttributeListener hsal1 = new MockHttpSessionAttributeListener();      
+      ctx = (Context) mgr1.getContainer();
+      ctx.setApplicationLifecycleListeners(new Object[]{ hsl1 });  
+      ctx.setApplicationEventListeners(new Object[]{ hsal1 }); 
+      
+      // Initial request
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attributes, false);
+      SessionTestUtil.invokeRequest(mgr0, setHandler, null);
+      
+      validateNewSession(setHandler);
+      String sessionId = setHandler.getSessionId();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl0.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.CREATED, hsl0.invocations.get(0));
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.ADDED, hsal0.invocations.get(0));
+         assertEquals(2, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.BOUND, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(1));
+         
+         validateNoNotifications(null, null, hsl1, hsal1, null);
+         clearNotifications(hsl0, hsal0, null, null, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Modify attribute request
+      setHandler = new SetAttributesRequestHandler(newAttributes, false);
+      SessionTestUtil.invokeRequest(mgr0, setHandler, sessionId);
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.REPLACED, hsal0.invocations.get(0));
+         assertEquals(4, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.BOUND, SessionSpecListenerAttribute.invocations.get(1));
+         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(2));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(3));
+         
+         validateNoNotifications(hsl0, null, hsl1, hsal1, null);
+         clearNotifications(null, hsal0, null, null, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Passivate
+      Thread.sleep(1100);
+      
+      mgr0.backgroundProcess();
+      mgr1.backgroundProcess();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(0));
+         
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1, null);
+         clearNotifications(null, null, null, null, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Remove attribute request
+      RemoveAttributesRequestHandler removeHandler = new RemoveAttributesRequestHandler(newAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(mgr0, removeHandler, sessionId);
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.REMOVED, hsal0.invocations.get(0));
+         assertEquals(3, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(1));
+         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(2));
+         
+         validateNoNotifications(hsl0, null, hsl1, hsal1, null);
+         clearNotifications(null, hsal0, null, null, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Failover request
+      setHandler = new SetAttributesRequestHandler(attributes, false);
+      SessionTestUtil.invokeRequest(mgr1, setHandler, sessionId);
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl1.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.CREATED, hsl1.invocations.get(0));
+         assertEquals(1, hsal1.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.ADDED, hsal1.invocations.get(0));
+         assertEquals(2, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.BOUND, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(1));
+         
+         validateNoNotifications(hsl0, hsal0, null, null, null);
+         clearNotifications(null, null, hsl1, hsal1, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Passivate
+      Thread.sleep(1100);
+      
+      mgr0.backgroundProcess();
+      mgr1.backgroundProcess();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(0));
+         
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1, null);
+         clearNotifications(null, null, null, null, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Fail back and invalidate session after changing attribute
+      InvalidateSessionRequestHandler invalidateHandler = new InvalidateSessionRequestHandler(newAttributes.keySet(), false);
+      SessionTestUtil.invokeRequest(mgr0, invalidateHandler, sessionId);
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl0.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.DESTROYED, hsl0.invocations.get(0));
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.REMOVED, hsal0.invocations.get(0));
+         assertEquals(3, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(1));
+         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(2));
+         
+         validateNoNotifications(null, null, hsl1, hsal1, null);
+         clearNotifications(hsl0, hsal0, null, null, SessionSpecListenerAttribute.invocations);
+      }
+   }
+   
+   public void testSessionExpirationWithNotifications() throws Exception
+   {
+      log.info("++++ Starting testSessionExpirationWithNotifications ++++");
+      sessionExpirationTest(true);
+   }
+   
+   public void testSessionExpirationWithoutNotifications() throws Exception
+   {
+      log.info("++++ Starting testSessionExpirationWithoutNotifications ++++");
+      sessionExpirationTest(false);
+   }
+   
+   private void sessionExpirationTest(boolean notify) throws Exception
+   {
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 2 secs and a maxIdle of 1
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 2, 1);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      assertTrue(mgr0.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+      MockClusteredSessionNotificationPolicy mcsnp0 = (MockClusteredSessionNotificationPolicy) mgr0.getNotificationPolicy();
+      assertNotNull("capability set", mcsnp0.getClusteredSessionNotificationCapability());
+      mcsnp0.setResponse(notify);
+      
+      assertTrue(mgr1.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+      MockClusteredSessionNotificationPolicy mcsnp1 = (MockClusteredSessionNotificationPolicy) mgr1.getNotificationPolicy();
+      assertNotNull("capability set", mcsnp1.getClusteredSessionNotificationCapability());
+      mcsnp1.setResponse(notify);
+      
+      MockHttpSessionListener hsl0 = new MockHttpSessionListener();
+      MockHttpSessionAttributeListener hsal0 = new MockHttpSessionAttributeListener();      
+      Context ctx = (Context) mgr0.getContainer();
+      ctx.setApplicationLifecycleListeners(new Object[]{ hsl0 });  
+      ctx.setApplicationEventListeners(new Object[]{ hsal0 }); 
+      
+      MockHttpSessionListener hsl1 = new MockHttpSessionListener();
+      MockHttpSessionAttributeListener hsal1 = new MockHttpSessionAttributeListener();      
+      ctx = (Context) mgr1.getContainer();
+      ctx.setApplicationLifecycleListeners(new Object[]{ hsl1 });  
+      ctx.setApplicationEventListeners(new Object[]{ hsal1 }); 
+      
+      // Initial request
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attributes, false);
+      SessionTestUtil.invokeRequest(mgr0, setHandler, null);
+      
+      validateNewSession(setHandler);
+      
+      String sessionId = setHandler.getSessionId();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl0.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.CREATED, hsl0.invocations.get(0));
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.ADDED, hsal0.invocations.get(0));
+         assertEquals(2, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.BOUND, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(1));
+         
+         validateNoNotifications(null, null, hsl1, hsal1, null);
+         clearNotifications(hsl0, hsal0, null, null, SessionSpecListenerAttribute.invocations);         
+      }
+      
+      // Failover request
+      setHandler = new SetAttributesRequestHandler(newAttributes, false);
+      SessionTestUtil.invokeRequest(mgr1, setHandler, sessionId);
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl1.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.CREATED, hsl1.invocations.get(0));
+         assertEquals(1, hsal1.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.REPLACED, hsal1.invocations.get(0));
+         assertEquals(4, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.BOUND, SessionSpecListenerAttribute.invocations.get(1));
+         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(2));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(3));
+         
+         validateNoNotifications(hsl0, hsal0, null, null, null);
+         clearNotifications(null, null, hsl1, hsal1, SessionSpecListenerAttribute.invocations);         
+      }
+      
+      // Passivate
+      Thread.sleep(1100);
+      
+      log.info("passivating mgr0");
+      mgr0.backgroundProcess();
+      log.info("passivating mgr1");
+      mgr1.backgroundProcess();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(2, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(1));
+         
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1, null);
+         clearNotifications(null, null, null, null, SessionSpecListenerAttribute.invocations);
+      }
+      
+      // Expire
+      Thread.sleep(1000);
+      
+      log.info("expiring mgr0");
+      mgr0.backgroundProcess();
+      log.info("expiring mgr1");
+      mgr1.backgroundProcess();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         // With a persistent manager we don't expect invocations from
+         // mgr1. When mgr0 invalidates the session, it is gone from the
+         // DB, which prevents mgr1 "activating" it to issue notifications.
+         assertEquals(1, hsl0.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.DESTROYED, hsl0.invocations.get(0));
+         assertEquals(0, hsl1.invocations.size());
+//         assertEquals(1, hsl1.invocations.size());
+//         assertEquals(MockHttpSessionListener.Type.DESTROYED, hsl1.invocations.get(0));
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.REMOVED, hsal0.invocations.get(0));
+         assertEquals(0, hsal1.invocations.size());
+//         assertEquals(1, hsal1.invocations.size());
+//         assertEquals(MockHttpSessionAttributeListener.Type.REMOVED, hsal1.invocations.get(0));
+//         assertEquals(4, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(2, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(1));
+//         assertEquals(SessionSpecListenerAttribute.Type.ACTIVATING, SessionSpecListenerAttribute.invocations.get(2));
+//         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(3));
+         
+         validateNoNotifications(null, null, null, null, null);
+         clearNotifications(hsl0, hsal0, hsl1, hsal1, SessionSpecListenerAttribute.invocations);
+      }
+   }
+   
+   public void testUndeployWithNotifications() throws Exception
+   {
+      log.info("++++ Starting testUndeployWithNotifications ++++");
+      undeployTest(true);
+   }
+   
+   public void testUndeployWithoutNotifications() throws Exception
+   {
+      log.info("++++ Starting testUndeployWithoutNotifications ++++");
+      undeployTest(false);
+   }
+   
+   private void undeployTest(boolean notify) throws Exception
+   {
+      String warname = String.valueOf(++testId);
+      
+      // A war with a maxInactive of 30 mins and no maxIdle
+      DataSourcePersistentManager[] mgrs = getCacheManagers(warname, 1800, -1);
+      DataSourcePersistentManager mgr0 = mgrs[0];
+      DataSourcePersistentManager mgr1 = mgrs[1];
+      
+      assertTrue(mgr0.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+      MockClusteredSessionNotificationPolicy mcsnp0 = (MockClusteredSessionNotificationPolicy) mgr0.getNotificationPolicy();
+      assertNotNull("capability set", mcsnp0.getClusteredSessionNotificationCapability());
+      mcsnp0.setResponse(notify);
+      
+      assertTrue(mgr1.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+      MockClusteredSessionNotificationPolicy mcsnp1 = (MockClusteredSessionNotificationPolicy) mgr1.getNotificationPolicy();
+      assertNotNull("capability set", mcsnp1.getClusteredSessionNotificationCapability());
+      mcsnp1.setResponse(notify);
+      
+      MockHttpSessionListener hsl0 = new MockHttpSessionListener();
+      MockHttpSessionAttributeListener hsal0 = new MockHttpSessionAttributeListener();      
+      Context ctx = (Context) mgr0.getContainer();
+      ctx.setApplicationLifecycleListeners(new Object[]{ hsl0 });  
+      ctx.setApplicationEventListeners(new Object[]{ hsal0 });  
+      
+      MockHttpSessionListener hsl1 = new MockHttpSessionListener();
+      MockHttpSessionAttributeListener hsal1 = new MockHttpSessionAttributeListener();      
+      ctx = (Context) mgr1.getContainer();
+      ctx.setApplicationLifecycleListeners(new Object[]{ hsl1 });  
+      ctx.setApplicationEventListeners(new Object[]{ hsal1 }); 
+      
+      // Initial request
+      SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attributes, false);
+      SessionTestUtil.invokeRequest(mgr0, setHandler, null);
+      
+      validateNewSession(setHandler);
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl0.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.CREATED, hsl0.invocations.get(0));
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.ADDED, hsal0.invocations.get(0));
+         assertEquals(2, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.BOUND, SessionSpecListenerAttribute.invocations.get(0));
+         assertEquals(SessionSpecListenerAttribute.Type.PASSIVATED, SessionSpecListenerAttribute.invocations.get(1));
+         
+         validateNoNotifications(null, null, hsl1, hsal1, null);
+         clearNotifications(hsl0, hsal0, null, null, SessionSpecListenerAttribute.invocations);
+         
+      }
+      
+      mgr0.stop();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         assertEquals(1, hsl0.invocations.size());
+         assertEquals(MockHttpSessionListener.Type.DESTROYED, hsl0.invocations.get(0));
+         assertEquals(1, hsal0.invocations.size());
+         assertEquals(MockHttpSessionAttributeListener.Type.REMOVED, hsal0.invocations.get(0));
+         assertEquals(1, SessionSpecListenerAttribute.invocations.size());
+         assertEquals(SessionSpecListenerAttribute.Type.UNBOUND, SessionSpecListenerAttribute.invocations.get(0));
+         
+         validateNoNotifications(null, null, hsl1, hsal1, null);
+         clearNotifications(hsl0, hsal0, null, null, SessionSpecListenerAttribute.invocations);
+         
+         
+      }
+      
+      mgr1.stop();
+      
+      if (!notify)
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+      else
+      {
+         validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+      }
+   }
+   
+   private void validateNoNotifications(MockHttpSessionListener hsl0, MockHttpSessionAttributeListener hsal0,
+         MockHttpSessionListener hsl1, MockHttpSessionAttributeListener hsal1)
+   {
+      validateNoNotifications(hsl0, hsal0, hsl1, hsal1, SessionSpecListenerAttribute.invocations);
+   }
+   
+   private void validateNoNotifications(MockHttpSessionListener hsl0, MockHttpSessionAttributeListener hsal0,
+         MockHttpSessionListener hsl1, MockHttpSessionAttributeListener hsal1, List<SessionSpecListenerAttribute.Type> sspalis)
+   {
+      if (hsl0 != null)
+      {
+         assertEquals(0, hsl0.invocations.size());
+      }
+      if (hsal0 != null)
+      {
+         assertEquals(0, hsal0.invocations.size());
+      }
+      if (hsl1 != null)
+      {
+         assertEquals(0, hsl1.invocations.size());
+      }
+      if (hsal1 != null)
+      {
+         assertEquals(0, hsal1.invocations.size());
+      }
+      
+      if (sspalis != null)
+      {
+         assertEquals(0, sspalis.size());         
+      }
+      
+      clearNotifications(hsl0, hsal0, hsl1, hsal1, sspalis);
+   }
+   
+   private void clearNotifications(MockHttpSessionListener hsl0, MockHttpSessionAttributeListener hsal0,
+         MockHttpSessionListener hsl1, MockHttpSessionAttributeListener hsal1, List<SessionSpecListenerAttribute.Type> sspalis)
+   {      
+
+      if (hsl0 != null)
+      {
+         hsl0.invocations.clear();
+      }
+      if (hsal0 != null)
+      {
+         hsal0.invocations.clear();
+      }
+      if (hsl1 != null)
+      {
+         hsl1.invocations.clear();
+      }
+      if (hsal1 != null)
+      {
+         hsal1.invocations.clear();
+      }
+      
+      if (sspalis != null)
+      {
+         sspalis.clear();         
+      }
+   }
+   
+   protected DataSourcePersistentManager[] getCacheManagers(String warname, int maxInactive, int maxIdle)
+      throws Exception
+   {
+      DataSourcePersistentManager mgr0 = PersistentSessionTestUtil.createManager(warname, maxInactive, null);
+      PersistentSessionTestUtil.configureManager(mgr0, getReplicationGranularity(), getReplicationTrigger(), -1, maxIdle > 0, maxIdle, -1 ,false, 0);
+      mgr0.setSessionNotificationPolicyClass(MockClusteredSessionNotificationPolicy.class.getName());
+      this.managers.add(mgr0);
+      mgr0.start();
+      
+      DataSourcePersistentManager mgr1 = PersistentSessionTestUtil.createManager(warname, maxInactive, null);
+      PersistentSessionTestUtil.configureManager(mgr1, getReplicationGranularity(), getReplicationTrigger(), -1, true, maxIdle, -1 ,false, 0);
+      mgr1.setSessionNotificationPolicyClass(MockClusteredSessionNotificationPolicy.class.getName());
+      this.managers.add(mgr1);
+      mgr1.start();
+      
+      return new DataSourcePersistentManager[]{mgr0, mgr1};
+   }
+   
+   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());
+   }
+   
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/PersistentStoreSessionNotificationPolicyTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/PersistentManagerCrossContextCallsTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/PersistentManagerCrossContextCallsTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/PersistentManagerCrossContextCallsTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,51 @@
+/*
+ * 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.web.test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.Test;
+
+import org.jboss.test.cluster.testutil.DBSetupDelegate;
+import org.jboss.test.cluster.testutil.TestSetupDelegate;
+import org.jboss.test.cluster.web.JBossClusteredWebTestCase;
+import org.jboss.test.cluster.web.persistent.PersistentStoreSetupDelegate;
+
+public class PersistentManagerCrossContextCallsTestCase extends CrossContextCallsTestCase
+{
+
+   public PersistentManagerCrossContextCallsTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test suite() throws Exception
+   {
+      TestSetupDelegate dbDelegate = new DBSetupDelegate();
+      TestSetupDelegate storeDelegate = new PersistentStoreSetupDelegate();
+      List<TestSetupDelegate> list = Arrays.asList(new TestSetupDelegate[]{dbDelegate, storeDelegate});
+      return JBossClusteredWebTestCase.getDeploySetup(PersistentManagerCrossContextCallsTestCase.class,
+                                                      "disable-manager-override.beans, httpsession-ds.xml, " +
+                                                      "http-cross-ctx-persistent.ear", list);
+   }
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/defaultcfg/web/test/PersistentManagerCrossContextCallsTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Modified: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetup.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetup.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetup.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -21,18 +21,11 @@
  */
 package org.jboss.test.cluster.testutil;
 
-import java.sql.DriverManager;
-import java.sql.Connection;
-import java.sql.Statement;
-import java.io.File;
-import java.io.IOException;
-
-import org.jboss.test.JBossTestClusteredSetup;
-
-import junit.extensions.TestSetup;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
+import org.jboss.test.JBossTestClusteredSetup;
+
 /** A TestSetup that starts hypersonic before the testcase with a tcp
  * listening port at 1701.
  * 
@@ -41,9 +34,12 @@
  */
 public class DBSetup extends JBossTestClusteredSetup
 {
+   private final TestSetupDelegate delegate;
+   
    public DBSetup(Test test, String jarNames) throws Exception
    {
       super(test, jarNames);
+      this.delegate = new DBSetupDelegate();
    }
 
    public static Test getDeploySetup(final Test test, final String jarNames)
@@ -52,7 +48,7 @@
       return new DBSetup(test, jarNames);
    }
 
-   public static Test getDeploySetup(final Class clazz, final String jarNames)
+   public static Test getDeploySetup(final Class<?> clazz, final String jarNames)
       throws Exception
    {
       TestSuite suite = new TestSuite();
@@ -62,40 +58,8 @@
 
    protected void setUp() throws Exception
    {
-         File hypersoniDir = new File("output/hypersonic");
-         if (!hypersoniDir.exists())
-         {
-            hypersoniDir.mkdirs();
-         }
-
-         if (!hypersoniDir.isDirectory())
-         {
-            throw new IOException("Failed to create directory: " + hypersoniDir);
-         }
-      
-         File dbPath = new File(hypersoniDir, "cif-db");
-
-         // Start DB in new thread, or else it will block us
-         DBThread serverThread = new DBThread(dbPath);
-         serverThread.start();
+         delegate.setUp();
          
-         int elapsed = 0;
-         while (!serverThread.isStarted() && elapsed < 15000)
-         {
-            try 
-            {
-               Thread.sleep(100);
-               elapsed += 100;
-            }
-            catch (InterruptedException ie)
-            {
-               System.out.println("Interrupted while waiting for Hypersonic");
-            }
-         }
-         
-         if (!serverThread.isStarted())
-            System.out.println("Hypersonic failed to start in a timely fashion");
-         
          super.setUp();
    }
 
@@ -107,11 +71,7 @@
       }
       finally
       {
-         Class.forName("org.hsqldb.jdbcDriver");
-         String dbURL = "jdbc:hsqldb:hsql://localhost:1701";
-         Connection conn = DriverManager.getConnection(dbURL, "sa", "");
-         Statement statement = conn.createStatement();      
-         statement.executeQuery("SHUTDOWN COMPACT");
+         delegate.tearDown();
       }
       
    }
@@ -123,54 +83,4 @@
       Thread.sleep(120*1000);
       setup.tearDown();
    }
-   
-   class DBThread extends Thread
-   {
-      boolean started;
-      File dbPath;
-      
-      DBThread(File dbPath)
-      {
-         super("hypersonic");
-         this.dbPath = dbPath;
-      }
-      
-      boolean isStarted()
-      {
-         return started;
-      }
-      
-      public void run()
-      {
-         try
-         {
-            // Create startup arguments
-            // BES 2007/09/25 We use -silent true to avoid 
-            // http://sourceforge.net/tracker/index.php?func=detail&aid=1673747&group_id=23316&atid=378131
-            String[] args = {
-                  "-database",
-                  dbPath.toString(),
-                  "-port",
-                  String.valueOf(1701),
-                  "-silent",
-                  "true",
-                  "-trace",
-                  "false",
-                  "-no_system_exit",
-                  "true",
-             };
-            System.out.println("Starting hsqldb");
-            org.hsqldb.Server.main(args);
-            System.out.println("Done");
-         }
-         catch (Exception e)
-         {
-            e.printStackTrace();
-         }
-         finally
-         {
-            started = true;
-         }
-      }
-   }
 }

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetupDelegate.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetupDelegate.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetupDelegate.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,147 @@
+/*
+ * 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.io.File;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.Statement;
+
+import org.jboss.test.JBossTestServices;
+
+/** A TestSetup that starts hypersonic before the testcase with a tcp
+ * listening port at 1701.
+ * 
+ * @author Brian Stansberry
+ * @version $Revison:$
+ */
+public class DBSetupDelegate implements TestSetupDelegate
+{
+   public void setTestServices(JBossTestServices services)
+   {
+      // no-op      
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.test.cluster.testutil.TestSetupDelegate#setUp()
+    */
+   public void setUp() throws Exception
+   {
+         File hypersoniDir = new File("output/hypersonic");
+         if (!hypersoniDir.exists())
+         {
+            hypersoniDir.mkdirs();
+         }
+
+         if (!hypersoniDir.isDirectory())
+         {
+            throw new IOException("Failed to create directory: " + hypersoniDir);
+         }
+      
+         File dbPath = new File(hypersoniDir, "cif-db");
+
+         // Start DB in new thread, or else it will block us
+         DBThread serverThread = new DBThread(dbPath);
+         serverThread.start();
+         
+         int elapsed = 0;
+         while (!serverThread.isStarted() && elapsed < 15000)
+         {
+            try 
+            {
+               Thread.sleep(100);
+               elapsed += 100;
+            }
+            catch (InterruptedException ie)
+            {
+               System.out.println("Interrupted while waiting for Hypersonic");
+            }
+         }
+         
+         if (!serverThread.isStarted())
+            System.out.println("Hypersonic failed to start in a timely fashion");
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.test.cluster.testutil.TestSetupDelegate#tearDown()
+    */
+   public void tearDown() throws Exception
+   {
+      Class.forName("org.hsqldb.jdbcDriver");
+      String dbURL = "jdbc:hsqldb:hsql://localhost:1701";
+      Connection conn = DriverManager.getConnection(dbURL, "sa", "");
+      Statement statement = conn.createStatement();      
+      statement.executeQuery("SHUTDOWN COMPACT");      
+   }
+   
+   class DBThread extends Thread
+   {
+      boolean started;
+      File dbPath;
+      
+      DBThread(File dbPath)
+      {
+         super("hypersonic");
+         this.dbPath = dbPath;
+      }
+      
+      boolean isStarted()
+      {
+         return started;
+      }
+      
+      public void run()
+      {
+         try
+         {
+            // Create startup arguments
+            // BES 2007/09/25 We use -silent true to avoid 
+            // http://sourceforge.net/tracker/index.php?func=detail&aid=1673747&group_id=23316&atid=378131
+            String[] args = {
+                  "-database",
+                  dbPath.toString(),
+                  "-port",
+                  String.valueOf(1701),
+                  "-silent",
+                  "true",
+                  "-trace",
+                  "false",
+                  "-no_system_exit",
+                  "true",
+             };
+            System.out.println("Starting hsqldb");
+            org.hsqldb.Server.main(args);
+            System.out.println("Done");
+         }
+         catch (Exception e)
+         {
+            e.printStackTrace();
+         }
+         finally
+         {
+            started = true;
+         }
+      }
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DBSetupDelegate.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DelegatingClusteredTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DelegatingClusteredTestCase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DelegatingClusteredTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,178 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.testutil;
+
+import java.util.List;
+import java.util.ListIterator;
+import java.util.StringTokenizer;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.jboss.test.AbstractTestSetup;
+import org.jboss.test.JBossClusteredTestCase;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.JBossTestClusteredSetup;
+import org.jboss.test.JBossTestServices;
+
+/**
+ *  JBossClusteredTestCase extension that accepts a list of 
+ *  {@link TestSetupDelegate} that can be processed as part of setup/tearDown of 
+ *  the suite.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class DelegatingClusteredTestCase extends JBossClusteredTestCase
+{
+   /**
+    * @param name
+    */
+   public DelegatingClusteredTestCase(String name)
+   {
+      super(name);
+   }
+
+   public static Test getDeploySetup(Test test, String jarNames)
+       throws Exception
+   {
+       return getDeploySetup(test, jarNames, null);
+   }
+
+   public static Test getDeploySetup(Class<?> clazz, String jarNames)
+       throws Exception
+   {
+       return getDeploySetup(clazz, jarNames, null);
+   }
+
+   public static Test getDeploySetup(Test test, String jarNames, List<TestSetupDelegate> delegates)
+       throws Exception
+   {
+       return new DelegatingTestSetup(test, jarNames, delegates);
+   }
+
+   public static Test getDeploySetup(Class<?> clazz, String jarNames, List<TestSetupDelegate> delegates)
+       throws Exception
+   {
+       TestSuite suite = new TestSuite();
+       suite.addTest(new TestSuite(clazz));
+       return getDeploySetup(suite, jarNames, delegates);
+   }
+   
+   public static class DelegatingTestSetup extends JBossTestClusteredSetup
+   {
+      private final List<TestSetupDelegate> setupDelegates;
+      private String jarNames = null;
+      
+      /**
+       * @param test
+       * @throws Exception
+       */
+      public DelegatingTestSetup(Test test, String jarNames, List<TestSetupDelegate> delegates) throws Exception
+      {
+         super(test, jarNames);
+         this.jarNames = jarNames;
+         this.setupDelegates = delegates;
+      }
+      
+      @Override
+      protected void setUp() throws Exception
+      {     
+         super.setUp();        
+         
+         JBossTestServices services = this.delegate;
+         if (setupDelegates != null)
+         {
+            for (TestSetupDelegate setupDelegate : setupDelegates)
+            {
+               setupDelegate.setTestServices(services);
+               setupDelegate.setUp();
+            }
+         }
+         
+         deployJars();
+      }
+
+      @Override
+      protected void tearDown() throws Exception
+      {
+         try
+         {
+            undeployJars();
+         }
+         finally
+         {
+            try
+            {
+               if (setupDelegates != null)
+               {
+                  for (ListIterator<TestSetupDelegate> it = setupDelegates.listIterator(); it.hasPrevious(); )
+                  {
+                     TestSetupDelegate setupDelegate = it.previous();
+                     setupDelegate.tearDown();
+                  }
+               }
+            }
+            finally
+            {
+            
+               try
+               {
+                  super.tearDown();
+               }
+               finally
+               {
+                  AbstractTestSetup.delegate = null;
+               }
+            }
+         }
+      }
+      
+      private void deployJars() throws Exception
+      {      
+         JBossTestCase.deploymentException = null;
+         try
+         {
+            // deploy the comma seperated list of jars
+            StringTokenizer st = new StringTokenizer(jarNames, ", ");
+            while (st.hasMoreTokens())
+            {
+               String jarName = st.nextToken();
+               this.redeploy(jarName);
+               this.getLog().debug("deployed package: " + jarName);
+            }
+         }
+         catch (Exception ex)
+         {
+            // Throw this in testServerFound() instead.
+            JBossTestCase.deploymentException = ex;
+         }
+             
+         // wait a couple seconds to let the cluster stabilize
+         synchronized (this)
+         {
+            wait(2000);
+         }
+      }
+      
+      private void undeployJars() throws Exception
+      {
+         // deploy the comma seperated list of jars
+         StringTokenizer st = new StringTokenizer(jarNames, ", ");
+         String[] depoyments = new String[st.countTokens()];
+         for (int i = depoyments.length - 1; i >= 0; i--)
+            depoyments[i] = st.nextToken();
+         for (int i = 0; i < depoyments.length; i++)
+         {
+            String jarName = depoyments[i];
+            this.getLog().debug("Attempt undeploy of " + jarName);
+            this.undeploy(jarName);
+            this.getLog().debug("undeployed package: " + jarName);
+         }   
+      }
+
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/DelegatingClusteredTestCase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/TestSetupDelegate.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/TestSetupDelegate.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/TestSetupDelegate.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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 org.jboss.test.JBossTestServices;
+
+import junit.extensions.TestSetup;
+
+/**
+ * Class to which a {@link TestSetup} can delegate some or all of its
+ * setUp or tearDown work.
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public interface TestSetupDelegate
+{
+   /** 
+    * Provides the delegate with a reference to the JBossTestServices.
+    * Delegate can assume this will be invoked before setUp(). 
+    */
+   void setTestServices(JBossTestServices services);
+
+   /** Perform setUp work. */
+   void setUp() throws Exception;
+   /** Perform tearDown work. */
+   void tearDown() throws Exception;
+
+}
\ No newline at end of file


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/testutil/TestSetupDelegate.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossCacheConfigTestSetupDelegate.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossCacheConfigTestSetupDelegate.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossCacheConfigTestSetupDelegate.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,92 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web;
+
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+
+import org.jboss.logging.Logger;
+import org.jboss.test.JBossTestClusteredServices;
+import org.jboss.test.JBossTestServices;
+import org.jboss.test.cluster.testutil.TestSetupDelegate;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class JBossCacheConfigTestSetupDelegate implements TestSetupDelegate
+{
+   public static final String SYSTEM_PROPS_SVC = "jboss:type=Service,name=SystemProperties";
+   
+   private static final Logger log = Logger.getLogger(JBossCacheConfigTestSetupDelegate.class);
+   
+   private String cacheConfigName;
+   private String usePojoCache;
+   private JBossTestClusteredServices clusteredServices;
+
+   public void setTestServices(JBossTestServices services)
+   {
+      this.clusteredServices = (JBossTestClusteredServices) services;      
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.test.cluster.testutil.TestSetupDelegate#setUp()
+    */
+   public void setUp() throws Exception
+   {
+      
+      cacheConfigName = System.getProperty(CacheHelper.CACHE_CONFIG_PROP);  
+      usePojoCache = System.getProperty(CacheHelper.CACHE_TYPE_PROP, "false");
+      if (cacheConfigName != null || Boolean.parseBoolean(usePojoCache))
+      {
+         setServerSideCacheConfigProperties();
+      }
+   }
+
+   /* (non-Javadoc)
+    * @see org.jboss.test.cluster.testutil.TestSetupDelegate#tearDown()
+    */
+   public void tearDown() throws Exception
+   {
+      // TODO Auto-generated method stub
+
+   }
+   
+   private void setServerSideCacheConfigProperties() throws Exception
+   {
+      log.debug("configuring server with cacheConfigName=" + cacheConfigName + " and usePojoCache=" + usePojoCache);
+      
+      ObjectName on = new ObjectName(SYSTEM_PROPS_SVC);
+      for (MBeanServerConnection adaptor : clusteredServices.getAdaptors())
+      {
+         adaptor.invoke(on, "set", 
+                        new Object[]{CacheHelper.CACHE_CONFIG_PROP, cacheConfigName}, 
+                        new String[] {String.class.getName(), String.class.getName()});
+
+         adaptor.invoke(on, "set", 
+                        new Object[]{CacheHelper.CACHE_TYPE_PROP, usePojoCache}, 
+                        new String[] {String.class.getName(), String.class.getName()});
+      }         
+   }
+
+   private void clearServerSideCacheConfigProperties() throws Exception
+   {
+      ObjectName on = new ObjectName(SYSTEM_PROPS_SVC);
+      for (MBeanServerConnection adaptor : clusteredServices.getAdaptors())
+      {
+         adaptor.invoke(on, "remove", 
+                        new Object[]{CacheHelper.CACHE_CONFIG_PROP}, 
+                        new String[] {String.class.getName()});
+
+         adaptor.invoke(on, "remove", 
+                        new Object[] {CacheHelper.CACHE_TYPE_PROP}, 
+                        new String[] {String.class.getName()});
+      } 
+   }
+
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossCacheConfigTestSetupDelegate.java
___________________________________________________________________
Name: svn:keywords
   + 

Modified: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossClusteredWebTestCase.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossClusteredWebTestCase.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/JBossClusteredWebTestCase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -22,29 +22,25 @@
 
 package org.jboss.test.cluster.web;
 
-import java.util.StringTokenizer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
-import javax.management.MBeanServerConnection;
-import javax.management.ObjectName;
-
 import junit.framework.Test;
-import junit.framework.TestSuite;
 
 import org.jboss.test.AbstractTestDelegate;
-import org.jboss.test.AbstractTestSetup;
-import org.jboss.test.JBossClusteredTestCase;
-import org.jboss.test.JBossTestCase;
 import org.jboss.test.JBossTestClusteredServices;
-import org.jboss.test.JBossTestSetup;
+import org.jboss.test.cluster.testutil.DelegatingClusteredTestCase;
+import org.jboss.test.cluster.testutil.TestSetupDelegate;
 
 /**
  * @author Brian Stansberry
  *
  */
-public class JBossClusteredWebTestCase extends JBossClusteredTestCase
+public class JBossClusteredWebTestCase extends DelegatingClusteredTestCase
 {
 
-   public static AbstractTestDelegate getDelegate(Class clazz)
+   public static AbstractTestDelegate getDelegate(Class<?> clazz)
        throws Exception
    {
        return new JBossTestClusteredServices(clazz);
@@ -63,160 +59,200 @@
    public static Test getDeploySetup(Test test, String jarNames)
        throws Exception
    {
-       return new JBossClusteredWebTestSetup(test, jarNames);
+      return getDeploySetup(test, jarNames, null);
    }
 
-   public static Test getDeploySetup(Class clazz, String jarNames)
+   public static Test getDeploySetup(Class<?> clazz, String jarNames)
        throws Exception
    {
-       TestSuite suite = new TestSuite();
-       suite.addTest(new TestSuite(clazz));
-       return getDeploySetup(suite, jarNames);
+       return getDeploySetup(clazz, jarNames, null);
    }
-   
-   private static String getJarNamesWithHelper(String jarNames)
+
+   public static Test getDeploySetup(Test test, String jarNames, List<TestSetupDelegate> delegates)
+       throws Exception
    {
-      if (jarNames == null || jarNames.length() == 0)
-         return "jbosscache-helper.sar";
-      else
-         return "jbosscache-helper.sar, " + jarNames;
+      return DelegatingClusteredTestCase.getDeploySetup(test, getJarNamesWithHelper(jarNames), ensureJBCConfigDelegate(delegates));
    }
+
+   public static Test getDeploySetup(Class<?> clazz, String jarNames, List<TestSetupDelegate> delegates)
+       throws Exception
+   {
+       return DelegatingClusteredTestCase.getDeploySetup(clazz, getJarNamesWithHelper(jarNames), ensureJBCConfigDelegate(delegates));
+   }
    
-   public static class JBossClusteredWebTestSetup extends JBossTestSetup
+   private static List<TestSetupDelegate> ensureJBCConfigDelegate(List<TestSetupDelegate> delegates)
    {
-      public static final String SYSTEM_PROPS_SVC = "jboss:type=Service,name=SystemProperties";
-      
-      private String cacheConfigName;
-      private String usePojoCache;
-      private String jarNames = null;
-      private JBossTestClusteredServices clusteredServices;
-      
-      /**
-       * Create a new JBossTestClusteredWebSetup.
-       * 
-       * @param test
-       * @param jarNames
-       * @throws Exception
-       */
-      public JBossClusteredWebTestSetup(Test test, String jarNames) throws Exception
+      List<TestSetupDelegate> result = delegates;
+      if (result == null)
       {
-         super(JBossClusteredWebTestCase.class, test);
-         this.jarNames = getJarNamesWithHelper(jarNames);
+         result = Arrays.asList(new TestSetupDelegate[]{new JBossCacheConfigTestSetupDelegate()});
       }
-   
-      @Override
-      protected void setUp() throws Exception
-      {      
-         super.setUp();        
-         
-         getLog().debug("delegate is " + delegate);
-         
-         clusteredServices = (JBossTestClusteredServices) delegate;
-         
-         cacheConfigName = System.getProperty(CacheHelper.CACHE_CONFIG_PROP);  
-         usePojoCache = System.getProperty(CacheHelper.CACHE_TYPE_PROP, "false");
-         if (cacheConfigName != null || Boolean.parseBoolean(usePojoCache))
-         {
-            setServerSideCacheConfigProperties();
-         }
-         
-         deployJars();
-      }
-   
-      @Override
-      protected void tearDown() throws Exception
+      else
       {
-         try
+         boolean hasJBCConfig = false;
+         for (TestSetupDelegate setup : delegates)
          {
-            undeployJars();
-            
-            super.tearDown();
-            if (cacheConfigName != null)
+            if (setup instanceof JBossCacheConfigTestSetupDelegate)
             {
-               clearServerSideCacheConfigProperties();
+               hasJBCConfig = true;
+               break;
             }
          }
-         finally
-         {
-            AbstractTestSetup.delegate = null;
-         }
-      }
-   
-      private void setServerSideCacheConfigProperties() throws Exception
-      {
-         getLog().debug("configuring server with cacheConfigName=" + cacheConfigName + " and usePojoCache=" + usePojoCache);
          
-         ObjectName on = new ObjectName(SYSTEM_PROPS_SVC);
-         for (MBeanServerConnection adaptor : clusteredServices.getAdaptors())
+         if (!hasJBCConfig)
          {
-            adaptor.invoke(on, "set", 
-                           new Object[]{CacheHelper.CACHE_CONFIG_PROP, cacheConfigName}, 
-                           new String[] {String.class.getName(), String.class.getName()});
-
-            adaptor.invoke(on, "set", 
-                           new Object[]{CacheHelper.CACHE_TYPE_PROP, usePojoCache}, 
-                           new String[] {String.class.getName(), String.class.getName()});
-         }         
-      }
-   
-      private void clearServerSideCacheConfigProperties() throws Exception
-      {
-         ObjectName on = new ObjectName(SYSTEM_PROPS_SVC);
-         for (MBeanServerConnection adaptor : clusteredServices.getAdaptors())
-         {
-            adaptor.invoke(on, "remove", 
-                           new Object[]{CacheHelper.CACHE_CONFIG_PROP}, 
-                           new String[] {String.class.getName()});
-
-            adaptor.invoke(on, "remove", 
-                           new Object[] {CacheHelper.CACHE_TYPE_PROP}, 
-                           new String[] {String.class.getName()});
-         } 
-      }
-      
-      private void deployJars() throws Exception
-      {      
-         JBossTestCase.deploymentException = null;
-         try
-         {
-            // deploy the comma seperated list of jars
-            StringTokenizer st = new StringTokenizer(jarNames, ", ");
-            while (st.hasMoreTokens())
-            {
-               String jarName = st.nextToken();
-               this.redeploy(jarName);
-               this.getLog().debug("deployed package: " + jarName);
-            }
+            result = new ArrayList<TestSetupDelegate>(delegates);
+            result.add(0, new JBossCacheConfigTestSetupDelegate());
          }
-         catch (Exception ex)
-         {
-            // Throw this in testServerFound() instead.
-            JBossTestCase.deploymentException = ex;
-         }
-             
-         // wait a couple seconds to let the cluster stabilize
-         synchronized (this)
-         {
-            wait(2000);
-         }
       }
       
-      private void undeployJars() throws Exception
-      {
-         // deploy the comma seperated list of jars
-         StringTokenizer st = new StringTokenizer(jarNames, ", ");
-         String[] depoyments = new String[st.countTokens()];
-         for (int i = depoyments.length - 1; i >= 0; i--)
-            depoyments[i] = st.nextToken();
-         for (int i = 0; i < depoyments.length; i++)
-         {
-            String jarName = depoyments[i];
-            this.getLog().debug("Attempt undeploy of " + jarName);
-            this.undeploy(jarName);
-            this.getLog().debug("undeployed package: " + jarName);
-         }   
-      }
+      return result;
+   }
    
+   
+   private static String getJarNamesWithHelper(String jarNames)
+   {
+      if (jarNames == null || jarNames.length() == 0)
+         return "jbosscache-helper.sar";
+      else
+         return "jbosscache-helper.sar, " + jarNames;
    }
+   
+//   public static class JBossClusteredWebTestSetup extends JBossTestSetup
+//   {
+//      public static final String SYSTEM_PROPS_SVC = "jboss:type=Service,name=SystemProperties";
+//      
+//      private String cacheConfigName;
+//      private String usePojoCache;
+//      private String jarNames = null;
+//      private JBossTestClusteredServices clusteredServices;
+//      
+//      /**
+//       * Create a new JBossTestClusteredWebSetup.
+//       * 
+//       * @param test
+//       * @param jarNames
+//       * @throws Exception
+//       */
+//      public JBossClusteredWebTestSetup(Test test, String jarNames) throws Exception
+//      {
+//         super(JBossClusteredWebTestCase.class, test);
+//         this.jarNames = getJarNamesWithHelper(jarNames);
+//      }
+//   
+//      @Override
+//      protected void setUp() throws Exception
+//      {      
+//         super.setUp();        
+//         
+//         getLog().debug("delegate is " + delegate);
+//         
+//         clusteredServices = (JBossTestClusteredServices) delegate;
+//         
+//         cacheConfigName = System.getProperty(CacheHelper.CACHE_CONFIG_PROP);  
+//         usePojoCache = System.getProperty(CacheHelper.CACHE_TYPE_PROP, "false");
+//         if (cacheConfigName != null || Boolean.parseBoolean(usePojoCache))
+//         {
+//            setServerSideCacheConfigProperties();
+//         }
+//         
+//         deployJars();
+//      }
+//   
+//      @Override
+//      protected void tearDown() throws Exception
+//      {
+//         try
+//         {
+//            undeployJars();
+//            
+//            super.tearDown();
+//            if (cacheConfigName != null)
+//            {
+//               clearServerSideCacheConfigProperties();
+//            }
+//         }
+//         finally
+//         {
+//            AbstractTestSetup.delegate = null;
+//         }
+//      }
+//   
+//      private void setServerSideCacheConfigProperties() throws Exception
+//      {
+//         getLog().debug("configuring server with cacheConfigName=" + cacheConfigName + " and usePojoCache=" + usePojoCache);
+//         
+//         ObjectName on = new ObjectName(SYSTEM_PROPS_SVC);
+//         for (MBeanServerConnection adaptor : clusteredServices.getAdaptors())
+//         {
+//            adaptor.invoke(on, "set", 
+//                           new Object[]{CacheHelper.CACHE_CONFIG_PROP, cacheConfigName}, 
+//                           new String[] {String.class.getName(), String.class.getName()});
+//
+//            adaptor.invoke(on, "set", 
+//                           new Object[]{CacheHelper.CACHE_TYPE_PROP, usePojoCache}, 
+//                           new String[] {String.class.getName(), String.class.getName()});
+//         }         
+//      }
+//   
+//      private void clearServerSideCacheConfigProperties() throws Exception
+//      {
+//         ObjectName on = new ObjectName(SYSTEM_PROPS_SVC);
+//         for (MBeanServerConnection adaptor : clusteredServices.getAdaptors())
+//         {
+//            adaptor.invoke(on, "remove", 
+//                           new Object[]{CacheHelper.CACHE_CONFIG_PROP}, 
+//                           new String[] {String.class.getName()});
+//
+//            adaptor.invoke(on, "remove", 
+//                           new Object[] {CacheHelper.CACHE_TYPE_PROP}, 
+//                           new String[] {String.class.getName()});
+//         } 
+//      }
+//      
+//      private void deployJars() throws Exception
+//      {      
+//         JBossTestCase.deploymentException = null;
+//         try
+//         {
+//            // deploy the comma seperated list of jars
+//            StringTokenizer st = new StringTokenizer(jarNames, ", ");
+//            while (st.hasMoreTokens())
+//            {
+//               String jarName = st.nextToken();
+//               this.redeploy(jarName);
+//               this.getLog().debug("deployed package: " + jarName);
+//            }
+//         }
+//         catch (Exception ex)
+//         {
+//            // Throw this in testServerFound() instead.
+//            JBossTestCase.deploymentException = ex;
+//         }
+//             
+//         // wait a couple seconds to let the cluster stabilize
+//         synchronized (this)
+//         {
+//            wait(2000);
+//         }
+//      }
+//      
+//      private void undeployJars() throws Exception
+//      {
+//         // deploy the comma seperated list of jars
+//         StringTokenizer st = new StringTokenizer(jarNames, ", ");
+//         String[] depoyments = new String[st.countTokens()];
+//         for (int i = depoyments.length - 1; i >= 0; i--)
+//            depoyments[i] = st.nextToken();
+//         for (int i = 0; i < depoyments.length; i++)
+//         {
+//            String jarName = depoyments[i];
+//            this.getLog().debug("Attempt undeploy of " + jarName);
+//            this.undeploy(jarName);
+//            this.getLog().debug("undeployed package: " + jarName);
+//         }   
+//      }
+//   
+//   }
 
 }

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/ManagerOverrideDisabler.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/ManagerOverrideDisabler.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/ManagerOverrideDisabler.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import org.jboss.web.tomcat.service.deployers.TomcatDeployer;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class ManagerOverrideDisabler
+{
+   private final TomcatDeployer deployer;
+
+   /**
+    * 
+    */
+   public ManagerOverrideDisabler(TomcatDeployer deployer)
+   {
+      if (deployer == null)
+      {
+         throw new IllegalArgumentException("Null deployer");
+      }
+      this.deployer = deployer;
+   }
+   
+   public void start() throws Exception
+   {
+      this.deployer.setOverrideDistributableManager(false);
+   }
+   
+   public void stop() throws Exception
+   {
+      this.deployer.setOverrideDistributableManager(true);
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/ManagerOverrideDisabler.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockDataSource.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockDataSource.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockDataSource.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,79 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+/**
+ * Trivial DataSource impl that doesn't pool connections, simply creates them
+ * from a {@link Driver}.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class MockDataSource implements DataSource
+{
+   private PrintWriter logWriter;
+   private int loginTimeout;
+   
+   private final Driver driver;
+   private final String jdbcUrl;
+   private final String userName;
+   private final String password;
+   
+   public MockDataSource(Driver driver, String url, String username, String password)
+   {
+      this.driver = driver;
+      this.jdbcUrl = url;
+      this.userName = username;
+      this.password = password;
+   }
+   public Connection getConnection() throws SQLException
+   {
+      return getConnection(this.userName, this.password);
+   }
+
+   public Connection getConnection(String username, String password) throws SQLException
+   {
+      Properties props = new Properties();
+      if (username != null)
+      {
+         props.put("user", username);
+      }
+      if (password != null)
+      {
+         props.put("password", password);
+      }
+      Connection conn = driver.connect(this.jdbcUrl, props);
+      return conn;
+   }
+
+   public PrintWriter getLogWriter() throws SQLException
+   {
+      return this.logWriter;
+   }
+
+   public int getLoginTimeout() throws SQLException
+   {
+      return this.loginTimeout;
+   }
+
+   public void setLogWriter(PrintWriter out) throws SQLException
+   {
+      this.logWriter = out;
+   }
+
+   public void setLoginTimeout(int seconds) throws SQLException
+   {
+      this.loginTimeout = seconds;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockDataSource.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockOutgoingSessionData.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockOutgoingSessionData.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockOutgoingSessionData.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,38 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import java.util.Map;
+
+import org.jboss.web.tomcat.service.session.OutgoingDistributableSessionDataImpl;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class MockOutgoingSessionData 
+      extends OutgoingDistributableSessionDataImpl
+      implements OutgoingSessionGranularitySessionData
+{
+   private final Map<String, Object> attributes;
+   
+   public MockOutgoingSessionData(String realId, int version, 
+         Long timestamp, DistributableSessionMetadata metadata,
+         Map<String, Object> attributes)
+   {
+      super(realId, version, timestamp, metadata);
+      this.attributes = attributes;
+   }
+
+   public Map<String, Object> getSessionAttributes()
+   {
+      return attributes;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/MockOutgoingSessionData.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentSessionTestUtil.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentSessionTestUtil.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentSessionTestUtil.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,242 @@
+/*
+ * 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.web.persistent;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.sql.DataSource;
+
+import org.apache.catalina.core.StandardContext;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.metadata.web.jboss.SnapshotMode;
+import org.jboss.test.cluster.web.mocks.MockEngine;
+import org.jboss.test.cluster.web.mocks.MockHost;
+import org.jboss.web.tomcat.service.session.persistent.AbstractPersistentManager;
+import org.jboss.web.tomcat.service.session.persistent.DataSourcePersistentManager;
+import org.jboss.web.tomcat.service.session.persistent.RDBMSStoreBase;
+
+/**
+ * Utilities for session testing.
+ * 
+ * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
+ * @version $Revision: 81705 $
+ */
+public class PersistentSessionTestUtil
+{  
+//   private static final String[] STRING_ONLY_TYPES = { String.class.getName() };
+   private static DataSource datasource;
+   
+   public synchronized static DataSource getDataSource()
+   {
+      if (datasource == null)
+      {
+         try
+         {
+            Driver driver = org.hsqldb.jdbcDriver.class.newInstance();
+            String host = System.getProperty("node0.bind.address", "localhost");
+            String jdbcURL = "jdbc:hsqldb:hsql://" + host + ":1701";
+            datasource = new MockDataSource(driver, jdbcURL, "sa", null);
+         }
+         catch (InstantiationException e)
+         {
+            throw new RuntimeException("Failed to create DataSource", e);
+         }
+         catch (IllegalAccessException e)
+         {
+            throw new RuntimeException("Failed to create DataSource", e);
+         }
+      }
+      return datasource;
+   }
+   
+   public static DataSourcePersistentManager createManager(String warName, int maxInactiveInterval, 
+                                                 String jvmRoute)
+   {      
+      DataSourcePersistentManager mgr = new DataSourcePersistentManager(getDataSource());
+      mgr.setSnapshotMode(SnapshotMode.INSTANT);
+      
+      MockEngine engine = new MockEngine();
+      engine.setJvmRoute(jvmRoute);
+      MockHost host = new MockHost();
+      engine.addChild(host);
+      host.setName("localhost");
+      StandardContext container = new StandardContext();
+      container.setName(warName);
+      host.addChild(container);
+      container.setManager(mgr);
+      
+      // 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
+      mgr.setMaxInactiveInterval(maxInactiveInterval);
+   
+      return mgr;      
+   }
+   
+   public static void configureManager(AbstractPersistentManager mgr, int maxSessions)
+   {
+      configureManager(mgr,
+                       ReplicationGranularity.SESSION,
+                       ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET,
+                       maxSessions, false, -1, -1, false, 0);
+   } 
+   
+   public static void configureManager(AbstractPersistentManager mgr, int maxSessions, boolean passivation,
+         int maxIdle, int minIdle)
+   {
+      configureManager(mgr,
+            ReplicationGranularity.SESSION,
+                               ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET,
+                               maxSessions, passivation, maxIdle, minIdle, false, 60);
+   } 
+   
+   public static void configureManager(AbstractPersistentManager mgr, ReplicationGranularity granularity,
+                                                    ReplicationTrigger trigger,boolean batchMode,
+                                                    int maxUnreplicated)
+   {
+      configureManager(mgr, granularity, trigger, -1, false, 
+                       -1, -1, batchMode, maxUnreplicated);
+   } 
+   
+   public static void configureManager(AbstractPersistentManager mgr, 
+                                       ReplicationGranularity granularity,
+                                       ReplicationTrigger trigger,
+                                       int maxSessions, boolean passivation,
+                                       int maxIdle, int minIdle,
+                                       boolean batchMode,
+                                       int maxUnreplicated)
+   {
+      mgr.setMaxActiveAllowed(maxSessions);
+      mgr.setUseSessionPassivation(passivation);
+      mgr.setPassivationMaxIdleTime(maxIdle);
+      mgr.setPassivationMinIdleTime(minIdle);
+      mgr.setReplicationGranularity(granularity);
+      mgr.setReplicationTrigger(trigger);
+      mgr.setReplicationFieldBatchMode(batchMode);
+      mgr.setMaxUnreplicatedInterval(maxUnreplicated);
+   }
+   
+   public static Integer getSessionVersion(DataSource ds, String realId, String appName) throws Exception
+   {
+      String versionSql = "SELECT " + RDBMSStoreBase.DEFAULT_VERSION_COL + 
+            " FROM " + RDBMSStoreBase.DEFAULT_TABLE + 
+            " WHERE " + RDBMSStoreBase.DEFAULT_ID_COL + " = ? AND " + RDBMSStoreBase.DEFAULT_APP_COL + " = ?";
+      PreparedStatement stmt = null;
+      ResultSet rs = null;
+      Connection conn = ds.getConnection();
+      try
+      {
+         conn.setAutoCommit(true);
+         stmt = conn.prepareStatement(versionSql);
+         stmt.setString(1, realId);
+         stmt.setString(2, appName);
+         rs = stmt.executeQuery();
+         if (rs.next())
+         {
+            return Integer.valueOf(rs.getInt(1));
+         }
+         
+         return null;
+      }
+      finally
+      {
+         if (rs != null)
+         {
+            try
+            {
+               rs.close();
+            }
+            catch (Exception e)
+            {
+            }
+         }
+         if (stmt != null)
+         {
+            try
+            {
+               stmt.close();
+            }
+            catch (Exception e)
+            {
+            }
+         }
+         conn.close();
+      }
+      
+   }
+   
+   @SuppressWarnings("unchecked")
+   public static Set<String> getSessionIds(DataSource ds, String warName) throws Exception
+   {
+      String keysSql = "SELECT " + RDBMSStoreBase.DEFAULT_ID_COL + " FROM " + 
+      RDBMSStoreBase.DEFAULT_TABLE + " WHERE " + RDBMSStoreBase.DEFAULT_APP_COL + " = ?";
+      PreparedStatement stmt = null;
+      ResultSet rs = null;
+      Connection conn = ds.getConnection();
+      try
+      {
+         conn.setAutoCommit(true);
+         stmt = conn.prepareStatement(keysSql);
+         stmt.setString(1, warName);
+         rs = stmt.executeQuery();
+         Set<String> result = new HashSet<String>();
+         while (rs.next())
+         {
+            result.add((String) rs.getString(1));
+         }
+         
+         return result;
+      }
+      finally
+      {
+         if (rs != null)
+         {
+            try
+            {
+               rs.close();
+            }
+            catch (Exception e)
+            {
+            }
+         }
+         if (stmt != null)
+         {
+            try
+            {
+               stmt.close();
+            }
+            catch (Exception e)
+            {
+            }
+         }
+         conn.close();
+      }
+   }
+
+   private PersistentSessionTestUtil() {}
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentSessionTestUtil.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreSetupDelegate.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreSetupDelegate.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreSetupDelegate.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,42 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import org.jboss.test.JBossTestServices;
+import org.jboss.test.cluster.testutil.DBSetupDelegate;
+import org.jboss.test.cluster.testutil.TestSetupDelegate;
+import org.jboss.web.tomcat.service.session.persistent.PersistentStore;
+
+/**
+ * Extends {@link DBSetupDelegate} by using a {@link PersistentStoreTableSetup} to
+ * set up the storage table for use by the {@link PersistentStore}.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PersistentStoreSetupDelegate implements TestSetupDelegate
+{
+
+   public void setTestServices(JBossTestServices services)
+   {
+      // no-op
+   }
+
+   public void setUp() throws Exception
+   {
+      
+      PersistentStoreTableSetup tableSetup = new PersistentStoreTableSetup();
+      String host = System.getProperty("node0.bind.address", "localhost");
+      tableSetup.setJdbcURL("jdbc:hsqldb:hsql://" + host + ":1701");
+      tableSetup.start();
+   }
+
+   public void tearDown() throws Exception
+   {
+      // no-op
+   } 
+   
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreSetupDelegate.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTableSetup.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTableSetup.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTableSetup.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,146 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.Statement;
+import java.util.Properties;
+
+import javax.naming.InitialContext;
+import javax.sql.DataSource;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PersistentStoreTableSetup
+{
+   private static final String DEFAULT_DS = "java:DefaultDS";
+   
+   private static final String DEFAULT_DROP_DDL = "DROP TABLE httpsessions IF EXISTS";
+   
+   private static final String DEFAULT_CREATE_DDL = "CREATE TABLE httpsessions (" +
+   		"app VARCHAR(255) NOT NULL, " +
+   		"id VARCHAR(255) NOT NULL, " +
+   		"fullId VARCHAR(255) NOT NULL, " +
+   		"creationtime BIGINT NOT NULL, " +
+   		"maxinactive BIGINT NOT NULL, " +
+   		"version INT NOT NULL, " +
+   		"lastaccess BIGINT NOT NULL, " +
+   		"isnew CHAR(1) NOT NULL, " +
+   		"valid CHAR(1) NOT NULL, " +
+   		"metadata VARBINARY NULL, " +
+   		"attributes LONGVARBINARY NOT NULL " +
+//   		", CONSTRAINT app_id PRIMARY KEY (app, id)" +
+   		")";
+   // --------------------------------------------------------- Instance Fields
+   
+   private String jdbcURL;
+   
+   private String jndiName;
+   
+   private String createTableDDL;
+   
+   private String dropTableDDL;
+
+   // ------------------------------------------------------------- Properties
+
+   public String getDataSourceJndiName()
+   {
+      return jndiName == null ? DEFAULT_DS : jndiName;
+   }
+
+   public void setDataSourceJndiName(String jndiName)
+   {
+      this.jndiName = jndiName;
+   }
+
+   public String getJdbcURL()
+   {
+      return jdbcURL;
+   }
+
+   public void setJdbcURL(String jdbcURL)
+   {
+      this.jdbcURL = jdbcURL;
+   }
+
+   public String getCreateTableDDL()
+   {
+      return createTableDDL == null ? DEFAULT_CREATE_DDL : createTableDDL;
+   }
+
+   public void setCreateTableDDL(String createTableDDL)
+   {
+      this.createTableDDL = createTableDDL;
+   }
+
+   public String getDropTableDDL()
+   {
+      return dropTableDDL == null ? DEFAULT_DROP_DDL : dropTableDDL;
+   }
+
+   public void setDropTableDDL(String dropTableDDL)
+   {
+      this.dropTableDDL = dropTableDDL;
+   }
+   
+   
+   
+   // ------------------------------------------------------------------ Public
+
+   public void start() throws Exception
+   {
+      Connection conn = getConnection();
+      conn.setAutoCommit(false);
+      Statement stmt = null;
+      boolean success = false;
+      try
+      {
+         stmt = conn.createStatement();
+         stmt.execute(getDropTableDDL());
+         stmt.close();
+         stmt = conn.createStatement();
+         stmt.execute(getCreateTableDDL());
+         conn.commit();
+         success = true;
+      }
+      finally
+      {
+         if (!success)
+         {
+            conn.rollback();
+         }
+         if (stmt != null)
+         {
+            stmt.close();
+         }
+         conn.close();
+      }
+
+   }
+
+   private Connection getConnection() throws Exception
+   {
+      Connection conn = null;
+      if (jdbcURL != null)
+      {
+         Driver driver = org.hsqldb.jdbcDriver.class.newInstance();
+         Properties props = new Properties();
+         props.put("user", "sa");
+         conn = driver.connect(jdbcURL, props);
+      }
+      else
+      {
+         DataSource datasource = (DataSource) new InitialContext().lookup(getDataSourceJndiName());
+         conn = datasource.getConnection();
+      }
+      return conn;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTableSetup.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTestSetup.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTestSetup.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTestSetup.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,85 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.jboss.test.cluster.testutil.DBSetup;
+import org.jboss.test.cluster.testutil.TestSetupDelegate;
+import org.jboss.web.tomcat.service.session.persistent.PersistentStore;
+
+/**
+ * Extends {@link DBSetup} by using a {@link PersistentStoreTableSetupDelegate} to
+ * set up the storage table for use by the {@link PersistentStore}.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PersistentStoreTestSetup extends DBSetup
+{
+   private final List<TestSetupDelegate> delegates;
+
+   /**
+    * @param test
+    * @param jarNames
+    * @throws Exception
+    */
+   public PersistentStoreTestSetup(Test test, String jarNames, List<TestSetupDelegate> delegates) throws Exception
+   {
+      super(test, jarNames);
+      this.delegates = delegates;
+   }
+
+   public static Test getDeploySetup(final Test test, final String jarNames, final List<TestSetupDelegate> delegates)
+      throws Exception
+   {
+      return new PersistentStoreTestSetup(test, jarNames, delegates);
+   }
+
+   public static Test getDeploySetup(final Class<?> clazz, final String jarNames, final List<TestSetupDelegate> delegates)
+      throws Exception
+   {
+      TestSuite suite = new TestSuite();
+      suite.addTest(new TestSuite(clazz));
+      return getDeploySetup(suite, jarNames, delegates);
+   }
+
+   protected void setUp() throws Exception
+   {
+         if (delegates != null)
+         {
+            for (TestSetupDelegate delegate : delegates)
+            {
+               delegate.setUp();
+            }
+         }
+         
+         super.setUp();
+   }
+
+   protected void tearDown() throws Exception
+   {
+      try
+      {
+         super.tearDown();
+      }
+      finally
+      {
+         if (delegates != null)
+         {
+            for (TestSetupDelegate delegate : delegates)
+            {
+               delegate.tearDown();
+            }
+         }
+      }
+      
+   }
+   
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/PersistentStoreTestSetup.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/SimplePersistentStoreTestSetup.java
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/SimplePersistentStoreTestSetup.java	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/SimplePersistentStoreTestSetup.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,82 @@
+/**
+ * 
+ */
+package org.jboss.test.cluster.web.persistent;
+
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.jboss.test.cluster.testutil.DBSetup;
+import org.jboss.test.cluster.testutil.DBSetupDelegate;
+import org.jboss.web.tomcat.service.session.persistent.PersistentStore;
+
+/**
+ * Extends {@link DBSetup} by using a {@link PersistentStoreTableSetupDelegate} to
+ * set up the storage table for use by the {@link PersistentStore}.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class SimplePersistentStoreTestSetup extends TestSetup
+{
+   private final DBSetupDelegate dbDelegate;
+   private final PersistentStoreSetupDelegate tableDelegate;
+
+   /**
+    * @param test
+    * @param jarNames
+    * @throws Exception
+    */
+   public SimplePersistentStoreTestSetup(Test test) throws Exception
+   {
+      super(test);
+      this.dbDelegate = new DBSetupDelegate();
+      this.tableDelegate = new PersistentStoreSetupDelegate();
+   }
+
+   public static Test getDeploySetup(final Test test)
+      throws Exception
+   {
+      return new SimplePersistentStoreTestSetup(test);
+   }
+
+   public static Test getDeploySetup(final Class<?> clazz)
+      throws Exception
+   {
+      TestSuite suite = new TestSuite();
+      suite.addTest(new TestSuite(clazz));
+      return getDeploySetup(suite);
+   }
+
+   protected void setUp() throws Exception
+   {
+      dbDelegate.setUp();
+      tableDelegate.setUp();
+         
+      super.setUp();
+   }
+
+   protected void tearDown() throws Exception
+   {
+      try
+      {
+         super.tearDown();
+      }
+      finally
+      {
+         try
+         {
+            tableDelegate.tearDown();
+         }
+         finally
+         {
+            dbDelegate.tearDown();
+         }
+      }
+      
+   }
+   
+
+}


Property changes on: branches/JBPAPP_5_0/testsuite/src/main/org/jboss/test/cluster/web/persistent/SimplePersistentStoreTestSetup.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/META-INF/application.xml
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/META-INF/application.xml	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/META-INF/application.xml	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE application PUBLIC
+   "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN"
+   "http://java.sun.com/dtd/application_1_3.dtd">
+
+<application>
+   <display-name>DataSourcePersistentManager Cross Context Request Tests</display-name>
+
+   <module>
+      <web>
+         <web-uri>http-cross-ctx-first-persistent.war</web-uri>
+         <context-root>/http-cross-ctx-first</context-root>
+      </web>
+   </module>
+   <module>
+      <web>
+         <web-uri>http-cross-ctx-second-persistent.war</web-uri>
+         <context-root>/http-cross-ctx-second</context-root>
+      </web>
+   </module>
+   <module>
+      <web>
+         <web-uri>http-cross-ctx-third-persistent.war</web-uri>
+         <context-root>/http-cross-ctx-third</context-root>
+      </web>
+   </module>
+   
+</application>


Property changes on: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/META-INF/application.xml
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/WEB-INF/context.xml
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/WEB-INF/context.xml	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/WEB-INF/context.xml	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,12 @@
+<!-- Ensure cross-context is true, it's the default but lets be sure -->
+<Context cookies="true" crossContext="true">
+
+   <Manager className="org.jboss.web.tomcat.service.session.persistent.DataSourcePersistentManager"
+            dataSourceJndiName="java:HttpSessionDS"/>
+
+   <!-- Install an InstanceListener to handle the establishment of the run-as
+   role for servlet init/destroy events.
+   -->
+   <InstanceListener>org.jboss.web.tomcat.security.RunAsListener</InstanceListener>
+   
+</Context>
\ No newline at end of file


Property changes on: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/WEB-INF/context.xml
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/disable-manager-override-jboss-beans.xml
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/disable-manager-override-jboss-beans.xml	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/disable-manager-override-jboss-beans.xml	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0"> 
+
+   <!-- Tell the WarDeployer not to override the Manager -->
+   <bean name="ManagerOverrideDisabler" class="org.jboss.test.cluster.web.persistent.ManagerOverrideDisabler">
+      <constructor>
+         <parameter><inject bean="WarDeployer"/></parameter>
+      </constructor>
+   </bean>
+
+</deployment>
\ No newline at end of file


Property changes on: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/disable-manager-override-jboss-beans.xml
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/httpsession-ds.xml
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/httpsession-ds.xml	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/httpsession-ds.xml	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- The Hypersonic embedded database JCA connection factory config -->
+
+<!-- See http://www.jboss.org/community/wiki/Multiple1PC for information about local-tx-datasource -->
+<!-- $Id: hsqldb-ds.xml 88948 2009-05-15 14:09:08Z jesper.pedersen $ -->
+
+<datasources>
+   <local-tx-datasource>
+
+      <!-- The jndi name of the DataSource, it is prefixed with java:/ -->
+      <!-- Datasources are not available outside the virtual machine -->
+      <jndi-name>HttpSessionDS</jndi-name>
+
+      <!-- For server mode db, allowing other processes to use hsqldb over tcp.
+      This requires the org.jboss.jdbc.HypersonicDatabase mbean.-->
+      <connection-url>jdbc:hsqldb:hsql://${node0.bind.address:localhost}:1701</connection-url>
+      
+      <!-- For totally in-memory db, not saved when jboss stops. 
+      The org.jboss.jdbc.HypersonicDatabase mbean is required for proper db shutdown
+      <connection-url>jdbc:hsqldb:.</connection-url>
+      -->
+      <!-- For in-process persistent db, saved when jboss stops.
+      The org.jboss.jdbc.HypersonicDatabase mbean is required for proper db shutdown
+      
+      <connection-url>jdbc:hsqldb:${jboss.server.data.dir}${/}hypersonic${/}localDB</connection-url>
+-->
+      <!-- The driver class -->
+      <driver-class>org.hsqldb.jdbcDriver</driver-class>
+
+      <!-- The login and password -->
+      <user-name>sa</user-name>
+      <password></password>
+
+      <!--example of how to specify class that determines if exception means connection should be destroyed-->
+      <!--exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.DummyExceptionSorter</exception-sorter-class-name-->
+
+      <!-- this will be run before a managed connection is removed from the pool for use by a client-->
+      <!--<check-valid-connection-sql>select * from something</check-valid-connection-sql> -->
+
+      <!-- The minimum connections in a pool/sub-pool. Pools are lazily constructed on first use -->
+      <min-pool-size>5</min-pool-size>
+
+      <!-- The maximum connections in a pool/sub-pool -->
+      <max-pool-size>20</max-pool-size>
+
+      <!-- The time before an unused connection is destroyed -->
+      <!-- NOTE: This is the check period. It will be destroyed somewhere between 1x and 2x this timeout after last use -->
+      <!-- TEMPORARY FIX! - Disable idle connection removal, HSQLDB has a problem with not reaping threads on closed connections -->
+      <idle-timeout-minutes>0</idle-timeout-minutes>
+
+      <!-- sql to call when connection is created
+        <new-connection-sql>some arbitrary sql</new-connection-sql>
+      -->
+
+      <!-- sql to call on an existing pooled connection when it is obtained from pool 
+         <check-valid-connection-sql>some arbitrary sql</check-valid-connection-sql>
+      -->
+
+      <!-- example of how to specify a class that determines a connection is valid before it is handed out from the pool
+         <valid-connection-checker-class-name>org.jboss.resource.adapter.jdbc.vendor.DummyValidConnectionChecker</valid-connection-checker-class-name>
+      -->
+
+      <!-- Whether to check all statements are closed when the connection is returned to the pool,
+           this is a debugging feature that should be turned off in production -->
+      <track-statements/>
+
+      <!-- Use the getConnection(user, pw) for logins
+        <application-managed-security/>
+      -->
+
+      <!-- Use the security domain defined in conf/login-config.xml
+      <security-domain>HsqlDbRealm</security-domain>
+      -->
+
+      <!-- Use the security domain defined in conf/login-config.xml or the
+           getConnection(user, pw) for logins. The security domain takes precedence.
+        <security-domain-and-application>HsqlDbRealm</security-domain-and-application>
+      -->
+
+      <!-- HSQL DB benefits from prepared statement caching -->
+      <prepared-statement-cache-size>32</prepared-statement-cache-size>
+
+      <!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
+      <metadata>
+         <type-mapping>Hypersonic SQL</type-mapping>
+      </metadata>
+
+      <!-- When using in-process (standalone) mode
+      <depends>jboss:service=Hypersonic,database=localDB</depends>
+ -->
+      <!-- Uncomment when using hsqldb in server mode-->
+      <depends>jboss:service=Hypersonic</depends>
+      
+   </local-tx-datasource>
+
+   <!-- Uncomment if you want hsqldb accessed over tcp (server mode)-->
+   <mbean code="org.jboss.jdbc.HypersonicDatabase" 
+     name="jboss:service=Hypersonic">
+     <attribute name="Port">1701</attribute>
+     <attribute name="BindAddress">${jboss.bind.address}</attribute>     
+     <attribute name="Silent">true</attribute>
+     <attribute name="Database">default</attribute>
+     <attribute name="Trace">false</attribute>
+     <attribute name="No_system_exit">true</attribute>
+   </mbean>
+   
+
+   <!-- For hsqldb accessed from jboss only, in-process (standalone) mode  
+   <mbean code="org.jboss.jdbc.HypersonicDatabase" 
+     name="jboss:service=Hypersonic,database=localDB">
+     <attribute name="Database">localDB</attribute>
+     <attribute name="InProcessMode">true</attribute>
+   </mbean>
+   -->
+</datasources>


Property changes on: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/httpsession-ds.xml
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/rdbmsstore-tablesetup-jboss-beans.xml
===================================================================
--- branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/rdbmsstore-tablesetup-jboss-beans.xml	                        (rev 0)
+++ branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/rdbmsstore-tablesetup-jboss-beans.xml	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0"> 
+
+   <!-- Create the persistent store db table -->
+   <bean name="PersistentStoreTableSetup" class="org.jboss.test.cluster.web.persistent.PersistentStoreTableSetup">
+      <property name="jdbcURL">jdbc:hsqldb:hsql://localhost:1701</property>
+   </bean>
+
+</deployment>


Property changes on: branches/JBPAPP_5_0/testsuite/src/resources/cluster/persistent/rdbmsstore-tablesetup-jboss-beans.xml
___________________________________________________________________
Name: svn:keywords
   + 

Modified: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/DeployerConfig.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/DeployerConfig.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/DeployerConfig.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -119,6 +119,8 @@
 
    /** FQN of the SecurityContext Class */
    private String securityContextClassName;
+   
+   private boolean overrideDistributableManager = true;
 
    public ClassLoader getServiceClassLoader()
    {
@@ -311,4 +313,40 @@
    {
       this.sharedMetaData = sharedMetaData;
    }
+
+   /**
+    * Gets whether the session <code>Manager</code> implementation for 
+    * distributable webapps should be overridden with an instance of 
+    * {@link #getManagerClass()}.
+    * <p>
+    * Setting this to <code>false</code> allows custom configuration of
+    * a manager via a <code>context.xml</code>. Default is <code>true</code>.
+    * </p>
+    * 
+    * @return <code>true</code> if the manager should be overridden,
+    *         <code>false</code> if the existing manager should be retained.
+    */
+   public boolean getOverrideDistributableManager()
+   {
+      return overrideDistributableManager;
+   }
+
+   /**
+    * Sets whether the session <code>Manager</code> implementation for 
+    * distributable webapps should be overridden with an instance of 
+    * {@link #getManagerClass()}.
+    * <p>
+    * Setting this to <code>false</code> allows custom configuration of
+    * a manager via a <code>context.xml</code>.  Default is <code>true</code>.
+    * </p>
+    * 
+    * @param override <code>true</code> if the manager should be overridden,
+    *         <code>false</code> if the existing manager should be retained.
+    */
+   public void setOverrideDistributableManager(boolean override)
+   {
+      this.overrideDistributableManager = override;
+   }
+   
+   
 }

Modified: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -90,6 +90,9 @@
     * to true.
     */
    protected String managerClass = "org.jboss.web.tomcat.service.session.JBossCacheManager";
+   
+   /** Whether to override the Manager impl for distributable webapps */
+   private boolean overrideDistributableManager = true;
 
    /**
     * A flag indicating if the JBoss Loader should be used
@@ -169,6 +172,40 @@
       this.managerClass = managerClass;
    }
 
+   /**
+    * Gets whether the session <code>Manager</code> implementation for 
+    * distributable webapps should be overridden with an instance of 
+    * {@link #getManagerClass()}.
+    * <p>
+    * Setting this to <code>false</code> allows custom configuration of
+    * a manager via a <code>context.xml</code>. Default is <code>true</code>.
+    * </p>
+    * 
+    * @return <code>true</code> if the manager should be overridden,
+    *         <code>false</code> if the existing manager should be retained.
+    */
+   public boolean getOverrideDistributableManager()
+   {
+      return this.overrideDistributableManager;
+   }
+
+   /**
+    * Sets whether the session <code>Manager</code> implementation for 
+    * distributable webapps should be overridden with an instance of 
+    * {@link #getManagerClass()}.
+    * <p>
+    * Setting this to <code>false</code> allows custom configuration of
+    * a manager via a <code>context.xml</code>.  Default is <code>true</code>.
+    * </p>
+    * 
+    * @param override <code>true</code> if the manager should be overridden,
+    *         <code>false</code> if the existing manager should be retained.
+    */
+   public void setOverrideDistributableManager(boolean override)
+   {
+      this.overrideDistributableManager = override;
+   }
+
    public ClassLoader getServiceClassLoader()
    {
       return serviceClassLoader;
@@ -427,6 +464,7 @@
             ? getClass().getClassLoader()
             : getServiceClassLoader());
       config.setManagerClass(managerClass);
+      config.setOverrideDistributableManager(overrideDistributableManager);
       config.setJava2ClassLoadingCompliance(java2ClassLoadingCompliance);
       config.setUnpackWars(unpackWars);
       config.setLenientEjbLink(this.lenientEjbLink);

Modified: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployment.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployment.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/deployers/TomcatDeployment.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -332,7 +332,7 @@
       }
 
       // Clustering
-      if (metaData.getDistributable() != null)
+      if (config.getOverrideDistributableManager() && metaData.getDistributable() != null)
       {
          // Try to initate clustering, fallback to standard if no clustering is
          // available

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/AskSessionOutdatedSessionChecker.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/AskSessionOutdatedSessionChecker.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/AskSessionOutdatedSessionChecker.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,23 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class AskSessionOutdatedSessionChecker
+      implements  OutdatedSessionChecker
+{
+   public boolean isSessionOutdated(ClusteredSession<? extends OutgoingDistributableSessionData> session)
+   {
+      return session.isOutdated();
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/AskSessionOutdatedSessionChecker.java
___________________________________________________________________
Name: svn:keywords
   + 

Modified: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -677,6 +677,7 @@
       setPrincipal(null);
       isNew = false;
       isValid = false;
+      firstAccess = true;
       manager = null;
       
       listeners.clear();
@@ -1076,7 +1077,9 @@
       this.version.set(sessionData.getVersion());
       
       long ts = sessionData.getTimestamp();
-      this.lastAccessedTime = this.thisAccessedTime = ts;
+      long wasAccessed = this.thisAccessedTime;
+      this.lastAccessedTime = ts;
+      this.thisAccessedTime = ts;
       this.timestamp.set(ts);
       
       DistributableSessionMetadata md = sessionData.getMetadata();

Modified: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -156,6 +156,8 @@
 
    private Semaphore semaphore = new Semaphore(TOTAL_PERMITS, true);
    private Lock valveLock = new SemaphoreLock(this.semaphore);
+
+   private OutdatedSessionChecker outdatedSessionChecker;
    
    //  ----------------------------------------------------------  Constructors
 
@@ -497,13 +499,21 @@
 //          session.tellNew(ClusteredSessionNotificationCause.FAILOVER);
 //       }
       }
-      else if (session != null && session.isOutdated())
+      else if (session != null && this.outdatedSessionChecker.isSessionOutdated(session))
       {
          if (trace_)
             log_.trace("Updating session " + realId + " from the distributed cache");
          
          // Need to update it from the cache
-         loadSession(realId);
+         session = loadSession(realId);
+         if (session == null)
+         {
+            // We have a session locally but it's no longer available
+            // from the distributed store; i.e. it's been invalidated elsewhere
+            // So we need to clean up
+            // TODO what about notifications?
+            this.sessions_.remove(realId);
+         }
       }
 
       if (session != null)
@@ -611,8 +621,8 @@
    // -------------------------------------------------------  ClusteredManager
 
    /**
-    * Gets the <code>JBossCacheService</code> through which we interact
-    * with the <code>Cache</code>.
+    * Gets the <code>DistributedCacheManager</code> through which we interact
+    * with the distributed store.
     */
    public DistributedCacheManager<O> getDistributedCacheManager()
    {
@@ -849,22 +859,6 @@
    /**
     * {@inheritDoc}
     */
-   public long getPassivationMaxIdleTime()
-   {
-      return passivationMaxIdleTime_;
-   }
-
-   /**
-    * {@inheritDoc}
-    */
-   public long getPassivationMinIdleTime()
-   {
-      return passivationMinIdleTime_;
-   }
-
-   /**
-    * {@inheritDoc}
-    */
    public ReplicationGranularity getReplicationGranularity()
    {
       return replicationGranularity_;
@@ -1134,6 +1128,12 @@
    {
       this.snapshotMode_ = snapshotMode;
    }
+   
+   public void setSnapshotMode(String snapshotMode)
+   {
+      snapshotMode = (snapshotMode == null ? null : snapshotMode.toUpperCase());
+      setSnapshotMode(SnapshotMode.fromString(snapshotMode));
+   }
 
    /**
     * Sets whether the <code>Engine</code> in which we are running
@@ -1219,6 +1219,17 @@
       this.replicationFieldBatchMode_ = Boolean.valueOf(replicationFieldBatchMode);
    }
 
+   public String getSessionNotificationPolicyClass()
+   {
+      return notificationPolicyClass_;
+   }
+
+   public void setSessionNotificationPolicyClass(String notificationPolicyClass)
+   {
+      this.notificationPolicyClass_ = notificationPolicyClass;
+   }  
+   
+
    // --------------------------------------------------------------- Protected
 
 
@@ -1351,6 +1362,11 @@
       this.notificationPolicy_.setClusteredSessionNotificationCapability(new ClusteredSessionNotificationCapability());      
    }
    
+   protected OutdatedSessionChecker initOutdatedSessionChecker()
+   {
+      return new AskSessionOutdatedSessionChecker();      
+   }
+   
    /**
     * Gets the ids of all sessions in the distributed cache and adds
     * them to the unloaded sessions map, along with their lastAccessedTime
@@ -1536,7 +1552,7 @@
                   // JBAS-2403. Check for outdated sessions where we think
                   // the local copy has timed out.  If found, refresh the
                   // session from the cache in case that might change the timeout
-                  if (session.isOutdated() && !(session.isValid(false)))
+                  if (this.outdatedSessionChecker.isSessionOutdated(session) && !(session.isValid(false)))
                   {
                      // FIXME in AS 5 every time we get a notification from the distributed
                      // cache of an update, we get the latest timestamp. So
@@ -1583,20 +1599,20 @@
          // and permanently losing part of its node structure in JBoss Cache.
          long maxUnrep = maxUnreplicatedInterval_ < 0 ? 60 : maxUnreplicatedInterval_;
          
-         Map<String, OwnedSessionUpdate> unloaded = new HashMap<String, OwnedSessionUpdate>(unloadedSessions_);
+         Map<String, OwnedSessionUpdate> unloaded = getUnloadedSessions();
          for (Map.Entry<String, OwnedSessionUpdate> entry : unloaded.entrySet())
          {
             String realId = entry.getKey();
             OwnedSessionUpdate osu = entry.getValue();
             
             long now = System.currentTimeMillis();
-            long elapsed = (now - osu.updateTime);
+            long elapsed = (now - osu.getUpdateTime());
             try
             {
-               if (expire && osu.maxInactive >= 1 && elapsed >= (osu.maxInactive + maxUnrep) * 1000L)
+               if (expire && osu.getMaxInactive() >= 1 && elapsed >= (osu.getMaxInactive() + maxUnrep) * 1000L)
                {
                   //if (osu.passivated && osu.owner == null)
-                  if (osu.passivated)
+                  if (osu.isPassivated())
                   {
                      // Passivated session needs to be expired. A call to 
                      // findSession will bring it out of passivation
@@ -1611,12 +1627,12 @@
                   // If we get here either !osu.passivated, or we don't own
                   // the session or the session couldn't be reactivated (invalidated by user). 
                   // Either way, do a cleanup
-                  proxy_.removeSessionLocal(realId, osu.owner);
+                  proxy_.removeSessionLocal(realId, osu.getOwner());
                   unloadedSessions_.remove(realId);
                   stats_.removeStats(realId);
                   
                }
-               else if (passivate && !osu.passivated)
+               else if (passivate && !osu.isPassivated())
                {  
                   // we now have a valid session; store it so we can check later
                   // if we need to passivate it
@@ -1704,6 +1720,12 @@
    
    // ------------------------------------------------------ Session Management
 
+   protected Map<String, OwnedSessionUpdate> getUnloadedSessions()
+   {
+      Map<String, OwnedSessionUpdate> unloaded = new HashMap<String, OwnedSessionUpdate>(unloadedSessions_);
+      return unloaded;
+   }
+
    private ClusteredSession<? extends OutgoingDistributableSessionData> createEmptyClusteredSession()
    {     
 
@@ -1805,7 +1827,7 @@
          session = createEmptyClusteredSession();
          
          OwnedSessionUpdate osu = unloadedSessions_.get(realId);
-         passivated = (osu != null && osu.passivated);
+         passivated = (osu != null && osu.isPassivated());
       }
 
       synchronized (session)
@@ -2029,8 +2051,8 @@
          log_.trace("Passivating session with id: " + realId);
       }
 
-      proxy_.evictSession(realId, osu.owner);
-      osu.passivated = true;
+      proxy_.evictSession(realId, osu.getOwner());
+      osu.setPassivated(true);
       sessionPassivated();      
    }
    
@@ -2059,31 +2081,16 @@
          return;
       }
       
-      log_.info("Manager is about to start");      
+      log_.debug("Manager is about to start");      
 
       // Notify our interested LifecycleListeners
       lifecycle_.fireLifecycleEvent(BEFORE_START_EVENT, this);
       
-      if (snapshotMode_ == null) 
-      {
-         // We were not instantiated by a JBossCacheCluster, so we need to
-         // find one and let it configure our cluster-wide properties
-         try 
-         {
-            JBossCacheCluster cluster = (JBossCacheCluster) container_.getCluster();
-            cluster.configureManager(this);
-         }
-         catch (ClassCastException e)
-         {
-            String msg = "Cluster is not an instance of JBossCacheCluster";
-            log_.error(msg, e);
-            throw new LifecycleException(msg, e);
-         }
-      }      
+      configureUnembedded();            
       
       initClusteredSessionNotificationPolicy();
       
-      // Create the JBossCacheService
+      // Create the DistributedCacheManager
       try
       {
          if (replicationConfig_ == null)
@@ -2103,7 +2110,7 @@
       }
       catch (Throwable t)
       {
-         String str = "Problem starting JBossCacheService for Tomcat clustering";
+         String str = "Problem starting DistributedCacheManager for HttpSession clustering";
          log_.error(str, t);
          throw new LifecycleException(str, t);
       }
@@ -2111,15 +2118,21 @@
       batchingManager = proxy_.getBatchingManager();
       if(batchingManager == null)
       {
-         throw new LifecycleException("JBossCacheManager.start(): Obtain null batchingManager");
+         throw new LifecycleException("start(): Obtained null batchingManager");
       }
       
       try
-      {
+      {         
+         this.outdatedSessionChecker = initOutdatedSessionChecker();
          initializeUnloadedSessions();
+         
+         // Setup our SnapshotManager
+         initSnapshotManager();
 
          // Add SnapshotValve and, if needed, JvmRouteValve and batch repl valve
          installValves();
+         
+         backgroundProcessAllowed.set(true);
 
          started_ = true;
          
@@ -2129,7 +2142,7 @@
          // Let subclasses do what they want
          startExtensions();
          
-         log_.debug("start(): JBossCacheService started");
+         log_.debug("start(): DistributedCacheManager started");
       } 
       catch (Exception e)
       {
@@ -2139,7 +2152,31 @@
       
       registerManagerMBean();
    }
-   
+
+   protected void configureUnembedded() throws LifecycleException
+   {
+      if (snapshotMode_ == null)
+      {
+         // We were not instantiated by a JBossCacheCluster, so we need to
+         // find one and let it configure our cluster-wide properties
+         try 
+         {
+            JBossCacheCluster cluster = (JBossCacheCluster) container_.getCluster();
+            if (cluster == null)
+            {
+               cluster = new JBossCacheCluster();
+            }
+            cluster.configureManager(this);
+         }
+         catch (ClassCastException e)
+         {
+            String msg = "Cluster is not an instance of JBossCacheCluster";
+            log_.error(msg, e);
+            throw new LifecycleException(msg, e);
+         }
+      }
+   }
+
    private void synthesizeReplicationConfig()
    {
       ReplicationConfig cfg = new ReplicationConfig();
@@ -2276,9 +2313,9 @@
             {
                OwnedSessionUpdate osu = entry.getValue();
                // Ignore the marker entries for our passivated sessions
-               if (!osu.passivated)
+               if (!osu.isPassivated())
                {
-                  proxy_.evictSession(realId, osu.owner);
+                  proxy_.evictSession(realId, osu.getOwner());
                }
             }
             else
@@ -2307,8 +2344,9 @@
       super.start();
       
       initClusteredSessionNotificationPolicy();
+      this.outdatedSessionChecker = initOutdatedSessionChecker();
       
-      // Start the JBossCacheService
+      // Start the DistributedCacheManager
       // Will need to pass the classloader that is associated with this 
       // web app so de-serialization will work correctly.
       tcl_ = super.getContainer().getLoader().getClassLoader();
@@ -2339,7 +2377,7 @@
          // Let subclasses do what they want
          startExtensions();
 
-         log_.debug("start(): JBossCacheService started");         
+         log_.debug("start(): DistributedCacheManager started");         
       }
       catch (LifecycleException le)
       {
@@ -2405,22 +2443,6 @@
    
    // ------------------------------------------------------------ Inner Classes
    
-   private class OwnedSessionUpdate
-   {
-      String owner;
-      long updateTime;
-      int maxInactive;
-      boolean passivated;
-      
-      OwnedSessionUpdate(String owner, long updateTime, int maxInactive, boolean passivated)
-      {
-         this.owner = owner;
-         this.updateTime = updateTime;
-         this.maxInactive = maxInactive;
-         this.passivated = passivated;
-      }
-   }
-   
    private class PassivationCheck implements Comparable<PassivationCheck>
    {
       private final String realId;
@@ -2448,11 +2470,11 @@
       
       private long getLastUpdate()
       {
-         return osu == null ? session.getLastAccessedTimeInternal() : osu.updateTime;
+         return osu == null ? session.getLastAccessedTimeInternal() : osu.getUpdateTime();
       }
       
       private void passivate()
-      {
+      {         
          if (osu == null)
          {
             JBossCacheManager.this.processSessionPassivation(realId);

Modified: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossManager.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -90,14 +90,14 @@
     * than maxActiveAllowed_ sessions are in memory.
     * Setting to -1 means it's ignored.
     */
-   protected int passivationMinIdleTime_ = -1;
+   protected long passivationMinIdleTime_ = -1;
    
    /**
     * Max time (milliseconds) the session must be idle since lastAccesstime before 
     * it will be passivated if passivation is enabled.
     * Setting to -1 means session should not be forced out.
     */
-   protected int passivationMaxIdleTime_ = -1;
+   protected long passivationMaxIdleTime_ = -1;
    
    /**
     * The lifecycle_ event support for this component.
@@ -230,6 +230,36 @@
 
    // -------------------------------------------------------------- Properties
    
+   public boolean getUseSessionPassivation()
+   {
+      return passivationMode_;      
+   }
+   
+   public void setUseSessionPassivation(boolean enabled)
+   {
+      this.passivationMode_ = enabled;
+   }
+   
+   public long getPassivationMinIdleTime()
+   {
+      return passivationMinIdleTime_;
+   }
+
+   public void setPassivationMinIdleTime(long passivationMinIdleTime)
+   {
+      this.passivationMinIdleTime_ = passivationMinIdleTime;
+   }
+
+   public long getPassivationMaxIdleTime()
+   {
+      return passivationMaxIdleTime_;
+   }
+
+   public void setPassivationMaxIdleTime(long passivationMaxIdleTime)
+   {
+      this.passivationMaxIdleTime_ = passivationMaxIdleTime;
+   }
+   
    // ---------------------------------------------------- AbstractJBossManager
 
    /**
@@ -248,15 +278,15 @@
       {
          if (pConfig.getUseSessionPassivation() != null)
          {
-            passivationMode_ = pConfig.getUseSessionPassivation().booleanValue();
-            if (passivationMode_)
+            setUseSessionPassivation(pConfig.getUseSessionPassivation().booleanValue());
+            if (getUseSessionPassivation())
             {
                Integer min = pConfig.getPassivationMinIdleTime();
                if (min != null)
-                  passivationMinIdleTime_ = min.intValue();
+                  setPassivationMinIdleTime(min.intValue());
                Integer max = pConfig.getPassivationMaxIdleTime();
                if (max != null)
-                  passivationMaxIdleTime_ = max.intValue();
+                  setPassivationMaxIdleTime(max.intValue());
             }
          }
       }

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OutdatedSessionChecker.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OutdatedSessionChecker.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OutdatedSessionChecker.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,18 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public interface OutdatedSessionChecker
+{
+   boolean isSessionOutdated(ClusteredSession<? extends OutgoingDistributableSessionData> session);
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OutdatedSessionChecker.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OwnedSessionUpdate.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OwnedSessionUpdate.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OwnedSessionUpdate.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,45 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session;
+
+public class OwnedSessionUpdate
+{
+   private final String owner;
+   private final long updateTime;
+   private final int maxInactive;
+   private boolean passivated;
+
+   public OwnedSessionUpdate(String owner, long updateTime, int maxInactive, boolean passivated)
+   {
+      this.owner = owner;
+      this.updateTime = updateTime;
+      this.maxInactive = maxInactive;
+      this.passivated = passivated;
+   }
+   
+   public boolean isPassivated()
+   {
+      return passivated;
+   }
+
+   void setPassivated(boolean passivated)
+   {
+      this.passivated = passivated;
+   }
+
+   public String getOwner()
+   {
+      return owner;
+   }
+
+   public long getUpdateTime()
+   {
+      return updateTime;
+   }
+
+   public int getMaxInactive()
+   {
+      return maxInactive;
+   }
+}
\ No newline at end of file


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/OwnedSessionUpdate.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AbstractPersistentManager.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AbstractPersistentManager.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AbstractPersistentManager.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,539 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.catalina.LifecycleException;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.metadata.web.jboss.SnapshotMode;
+import org.jboss.web.tomcat.service.session.JBossCacheManager;
+import org.jboss.web.tomcat.service.session.OutdatedSessionChecker;
+import org.jboss.web.tomcat.service.session.OwnedSessionUpdate;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public abstract class AbstractPersistentManager<P extends RDBMSStoreBase, O extends OutgoingDistributableSessionData> 
+   extends JBossCacheManager<O>
+{
+   // ----------------------------------------------------- Instance Variables
+
+
+   /**
+    * The descriptive information about this implementation.
+    */
+   private static final String info = "AbstractPersistentManager/1.0";
+
+   /**
+    * The descriptive name of this Manager implementation (for logging).
+    */
+   protected static String name = "AbstractPersistentManager";
+   
+   private final P store;
+
+   /**
+    * The connection username to use when trying to connect to the database.
+    */
+   private String connectionName = null;
+
+   /**
+    * The connection URL to use when trying to connect to the database.
+    */
+   private String connectionPassword = null;
+
+   /**
+    * Table to use.
+    */
+   private String sessionTable = null;
+
+   /**
+    * Column to use for /Engine/Host/Context name
+    */
+   private String sessionAppCol = null;
+
+   /**
+    * Id column to use.
+    */
+   private String sessionIdCol = null;
+
+   /**
+    * Full Id (e.g. including jvmRoute) column to use.
+    */
+   private String sessionFullIdCol = null;
+
+   /**
+    * Creation time column to use
+    */
+   private String sessionCreationTimeCol = null;
+
+   /**
+    * Max Inactive column to use.
+    */
+   private String sessionMaxInactiveCol = null;
+
+   /**
+    * Version column to use.
+    */
+   private String sessionVersionCol = null;
+
+   /**
+    * Last Accessed column to use.
+    */
+   private String sessionLastAccessedCol = null;
+
+   /**
+    * Is New column to use
+    */
+   private String sessionNewCol = null;
+
+   /**
+    * Is Valid column to use.
+    */
+   private String sessionValidCol = null;
+
+   /**
+    * Column to use for misc metadata.
+    */
+   private String sessionMetadataCol = null;
+
+   /**
+    * Attribute column to use.
+    */
+   private String sessionAttributeCol = null;
+   
+   private Integer cleanupInterval = null;
+
+   private Logger log = Logger.getLogger(getClass());
+   
+   // ------------------------------------------------------------ Constructors
+
+   /**
+    * 
+    */
+   public AbstractPersistentManager(P store)
+   {
+      super(new PersistentStoreDistributedCacheManagerFactory(store));
+      
+      this.store = store;
+   }
+
+
+   // ------------------------------------------------------------- Properties
+
+
+   /**
+    * Return descriptive information about this Manager implementation and
+    * the corresponding version number, in the format
+    * <code>&lt;description&gt;/&lt;version&gt;</code>.
+    */
+   public String getInfo() {
+
+       return (info);
+
+   }
+
+   /**
+    * Return the descriptive short name of this Manager implementation.
+    */
+   public String getName() {
+
+       return (name);
+
+   }
+
+   public String getConnectionName()
+   {
+      return connectionName;
+   }
+
+
+   public void setConnectionName(String connectionName)
+   {
+      this.connectionName = connectionName;
+   }
+
+
+   public String getConnectionPassword()
+   {
+      return connectionPassword;
+   }
+
+
+   public void setConnectionPassword(String connectionPassword)
+   {
+      this.connectionPassword = connectionPassword;
+   }
+
+
+   public String getSessionTable()
+   {
+      return sessionTable;
+   }
+
+
+   public void setSessionTable(String sessionTable)
+   {
+      this.sessionTable = sessionTable;
+   }
+
+
+   public String getSessionAppCol()
+   {
+      return sessionAppCol;
+   }
+
+
+   public void setSessionAppCol(String sessionAppCol)
+   {
+      this.sessionAppCol = sessionAppCol;
+   }
+
+
+   public String getSessionIdCol()
+   {
+      return sessionIdCol;
+   }
+
+
+   public void setSessionIdCol(String sessionIdCol)
+   {
+      this.sessionIdCol = sessionIdCol;
+   }
+
+
+   public String getSessionFullIdCol()
+   {
+      return sessionFullIdCol;
+   }
+
+
+   public void setSessionFullIdCol(String sessionFullIdCol)
+   {
+      this.sessionFullIdCol = sessionFullIdCol;
+   }
+
+
+   public String getSessionCreationTimeCol()
+   {
+      return sessionCreationTimeCol;
+   }
+
+
+   public void setSessionCreationTimeCol(String sessionCreationTimeCol)
+   {
+      this.sessionCreationTimeCol = sessionCreationTimeCol;
+   }
+
+
+   public String getSessionMaxInactiveCol()
+   {
+      return sessionMaxInactiveCol;
+   }
+
+
+   public void setSessionMaxInactiveCol(String sessionMaxInactiveCol)
+   {
+      this.sessionMaxInactiveCol = sessionMaxInactiveCol;
+   }
+
+
+   public String getSessionVersionCol()
+   {
+      return sessionVersionCol;
+   }
+
+
+   public void setSessionVersionCol(String sessionVersionCol)
+   {
+      this.sessionVersionCol = sessionVersionCol;
+   }
+
+
+   public String getSessionLastAccessedCol()
+   {
+      return sessionLastAccessedCol;
+   }
+
+
+   public void setSessionLastAccessedCol(String sessionLastAccessedCol)
+   {
+      this.sessionLastAccessedCol = sessionLastAccessedCol;
+   }
+
+
+   public String getSessionNewCol()
+   {
+      return sessionNewCol;
+   }
+
+
+   public void setSessionNewCol(String sessionNewCol)
+   {
+      this.sessionNewCol = sessionNewCol;
+   }
+
+
+   public String getSessionValidCol()
+   {
+      return sessionValidCol;
+   }
+
+
+   public void setSessionValidCol(String sessionValidCol)
+   {
+      this.sessionValidCol = sessionValidCol;
+   }
+
+
+   public String getSessionMetadataCol()
+   {
+      return sessionMetadataCol;
+   }
+
+
+   public void setSessionMetadataCol(String sessionMetadataCol)
+   {
+      this.sessionMetadataCol = sessionMetadataCol;
+   }
+
+
+   public String getSessionAttributeCol()
+   {
+      return sessionAttributeCol;
+   }
+
+
+   public void setSessionAttributeCol(String sessionAttributeCol)
+   {
+      this.sessionAttributeCol = sessionAttributeCol;
+   }  
+   
+   public Integer getCleanupInterval()
+   {
+      return cleanupInterval;
+   }
+
+   public void setCleanupInterval(Integer cleanupInterval)
+   {
+      this.cleanupInterval = cleanupInterval;
+   }
+   
+   
+   
+   
+   
+   // --------------------------------------------------------------  Public
+
+
+   @Override
+   public void setReplicationGranularity(ReplicationGranularity granularity)
+   {
+      switch (granularity)
+      {
+         case SESSION:
+            super.setReplicationGranularity(granularity);
+            break;
+         default:
+            log.warn("Ignoring call to set replication granularity to " + 
+                  granularity + " -- only " + ReplicationGranularity.SESSION + " is supported");
+      }
+   }
+
+
+   @Override
+   public void start() throws LifecycleException
+   {
+      configureStore();
+      super.start();
+   }
+
+
+   // --------------------------------------------------------------  Protected
+
+   protected P getPersistentStore()
+   {
+      return store;
+   }
+   
+   @Override
+   protected void configureUnembedded() throws LifecycleException
+   {
+      // Only set replication attributes if they were not
+      // already set via a <Manager> element in an XML config file
+      
+      if (getReplicationGranularity() == null) 
+      {
+         setReplicationGranularity(ReplicationGranularity.SESSION);
+      }
+      
+      if (getReplicationTrigger() == null) 
+      {
+         setReplicationTrigger(ReplicationTrigger.SET_AND_NON_PRIMITIVE_GET);
+      }
+      
+      if (isReplicationFieldBatchMode() == null)
+      {
+         setReplicationFieldBatchMode(false);
+      }
+      
+      if (getSnapshotMode() == null)
+      {
+         setSnapshotMode(SnapshotMode.INSTANT);
+      }   
+   
+   }
+
+
+   protected void configureStore()
+   {
+      store.setName(this.getContextName());
+      
+      if (getConnectionName() != null)
+      {
+         store.setConnectionName(getConnectionName());
+      }
+      if (getConnectionPassword() != null)
+      {
+         store.setConnectionPassword(getConnectionPassword());
+      }
+      if (getSessionAppCol() != null)
+      {
+         store.setSessionAppCol(getSessionAppCol());
+      }
+      if (getSessionAttributeCol() != null)
+      {
+         store.setSessionAttributeCol(getSessionAttributeCol());
+      }
+      if (getSessionCreationTimeCol() != null)
+      {
+         store.setSessionCreationTimeCol(getSessionCreationTimeCol());
+      }
+      if (getSessionFullIdCol() != null)
+      {
+         store.setSessionFullIdCol(getSessionFullIdCol());
+      }
+      if (getSessionIdCol() != null)
+      {
+         store.setSessionIdCol(getSessionIdCol());
+      }
+      if (getSessionLastAccessedCol() != null)
+      {
+         store.setSessionLastAccessedCol(getSessionLastAccessedCol());
+      }
+      if (getSessionMaxInactiveCol() != null)
+      {
+         store.setSessionMaxInactiveCol(getSessionMaxInactiveCol());
+      }
+      if (getSessionMetadataCol() != null)
+      {
+         store.setSessionMetadataCol(getSessionMetadataCol());
+      }
+      if (getSessionNewCol() != null)
+      {
+         store.setSessionNewCol(getSessionNewCol());
+      }
+      if (getSessionTable() != null)
+      {
+         store.setSessionTable(getSessionTable());
+      }
+      if (getSessionValidCol() != null)
+      {
+         store.setSessionValidCol(getSessionValidCol());
+      }
+      if (getSessionVersionCol() != null)
+      {
+         store.setSessionVersionCol(getSessionVersionCol());
+      }
+      if (getCleanupInterval() != null)
+      {
+         store.setCleanupInterval(getCleanupInterval().intValue());
+      }
+   }
+
+
+   /**
+    * Overrides superclass to update the contents of OwnedSessionUpdate values
+    * to reflect the current state of the {@link PersistentStore}.
+    */
+   @Override
+   protected Map<String, OwnedSessionUpdate> getUnloadedSessions()
+   {
+      Map<String, OwnedSessionUpdate> map =  super.getUnloadedSessions();
+      Map<String, OwnedSessionUpdate> processed = new HashMap<String, OwnedSessionUpdate>();
+      for (Map.Entry<String, OwnedSessionUpdate> entry : map.entrySet())
+      {
+         String realId = entry.getKey();
+         OwnedSessionUpdate existing = entry.getValue();
+         
+         Long timestamp = store.getSessionTimestamp(realId);
+         if (timestamp != null && existing.getUpdateTime() != timestamp.longValue())
+         {
+            // Timestamp change -- pull in the data
+            IncomingDistributableSessionData data = store.getSessionData(entry.getKey(), false);
+            if (data != null)
+            {
+                OwnedSessionUpdate updated = new OwnedSessionUpdate(existing.getOwner(), 
+                      data.getTimestamp(), 
+                      data.getMetadata().getMaxInactiveInterval(), 
+                      existing.isPassivated());
+                
+                processed.put(realId, updated);
+            }
+            else
+            {
+               // Session has been deleted; just keep existing and let
+               // the caller clean up
+               processed.put(realId, existing);
+            }
+         }
+         else
+         {
+            // Session has been deleted; just keep existing and let
+            // the caller clean up
+            processed.put(realId, existing);
+         }
+      }
+      
+      return processed;
+   }
+
+
+   @Override
+   protected void initializeUnloadedSessions()
+   {
+      // no-op
+   }
+
+   
+
+   @Override
+   protected OutdatedSessionChecker initOutdatedSessionChecker()
+   {
+      // TODO make this configurable
+      return new VersionBasedOutdatedSessionChecker((ExtendedDistributedCacheManager<? extends OutgoingDistributableSessionData>) getDistributedCacheManager());
+   }
+
+
+   @Override
+   protected void processExpirationPassivation()
+   {
+      super.processExpirationPassivation();
+      
+      this.store.processExpires();
+   }
+   
+   
+
+   
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AbstractPersistentManager.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AlwaysTrueOutdatedSessionChecker.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AlwaysTrueOutdatedSessionChecker.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AlwaysTrueOutdatedSessionChecker.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import org.jboss.web.tomcat.service.session.ClusteredSession;
+import org.jboss.web.tomcat.service.session.OutdatedSessionChecker;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class AlwaysTrueOutdatedSessionChecker
+      implements  OutdatedSessionChecker
+{
+   public boolean isSessionOutdated(ClusteredSession<? extends OutgoingDistributableSessionData> session)
+   {
+      return true;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/AlwaysTrueOutdatedSessionChecker.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentManager.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentManager.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentManager.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,60 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import javax.sql.DataSource;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class DataSourcePersistentManager<O extends OutgoingDistributableSessionData> 
+   extends AbstractPersistentManager<DataSourcePersistentStore, O>
+{
+
+
+   // --------------------------------------------------------- Instance Fields
+   
+   private String jndiName;
+
+   // ------------------------------------------------------------- Constructors
+   
+   public DataSourcePersistentManager()
+   {
+      super(new DataSourcePersistentStore());
+   }
+   
+   public DataSourcePersistentManager(DataSource datasource)
+   {
+      super(new DataSourcePersistentStore(datasource));
+   }
+
+   // ------------------------------------------------------------- Properties
+
+   public String getDataSourceJndiName()
+   {
+      return jndiName;
+   }
+
+   public void setDataSourceJndiName(String jndiName)
+   {
+      this.jndiName = jndiName;
+   }
+
+   // ------------------------------------------------------------- Protected
+
+   @Override
+   protected void configureStore()
+   {
+      super.configureStore();
+      DataSourcePersistentStore store = getPersistentStore();
+      store.setDataSourceJndiName(jndiName);
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentManager.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentStore.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentStore.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentStore.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,159 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.sql.DataSource;
+
+import org.apache.catalina.Store;
+
+/**
+ * A {@link Store} that uses a {@link DataSource} to obtain connections
+ * for persisting sessions to a relational database.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class DataSourcePersistentStore extends RDBMSStoreBase
+{
+   /**
+    * The descriptive information about this implementation.
+    */
+   private static final String info = "DataSourceStore/1.0";
+
+   private static final String storeName = "DataSourceStore";
+   
+   // --------------------------------------------------------- Instance Fields
+   
+   private String jndiName;
+
+
+   private DataSource injecteddatasource;
+   private DataSource datasource;
+
+   /**
+    * Creates a new DataSourcePersistentStore.
+    */
+   public DataSourcePersistentStore()
+   {
+      
+   }
+
+   /**
+    * Creates a new DataSourcePersistentStore that uses the given DataSource.
+    * This constructor is intended for testing.
+    * 
+    * @param datasource the datasource
+    */
+   public DataSourcePersistentStore(DataSource datasource)
+   {
+      this.injecteddatasource = datasource;
+   }
+   
+   
+   // ------------------------------------------------------------- Properties
+
+   public String getDataSourceJndiName()
+   {
+      return jndiName;
+   }
+
+   public void setDataSourceJndiName(String jndiName)
+   {
+      this.jndiName = jndiName;
+   }
+
+   @Override
+   public String getStoreName()
+   {
+      return (storeName);
+   }
+
+   // -------------------------------------------------------------- Protected
+
+   @Override
+   protected Connection getConnection() throws SQLException
+   {
+      try
+      {
+         Connection conn = null;
+         if (getConnectionName() != null)
+         {
+            conn = datasource.getConnection(getConnectionName(), getConnectionPassword());
+         }
+         else
+         {
+            conn = datasource.getConnection();
+         }
+         
+         conn.setAutoCommit(false);
+         return conn;
+      }
+      catch (SQLException e)
+      {
+         // perhaps our datasource has been restarted? Reacquire in case
+         try
+         {
+            findDataSource();
+         }
+         catch (Exception e1)
+         {
+            getLogger().error("Caught exception reacquiring datasource", e1);
+         }
+         throw e;
+      }      
+   }
+
+   @Override
+   public String getInfo()
+   {
+      return info;
+   }
+
+   @Override
+   protected void releaseConnection(Connection conn)
+   {
+      cleanup(conn, null, false);
+   }
+
+   @Override
+   protected void startStore()
+   {
+      findDataSource();
+   }
+   
+   private void findDataSource()
+   {
+      if (injecteddatasource == null)
+      {
+         if (jndiName == null)
+         {
+            throw new IllegalStateException("No jndiName has been configured");
+         }
+   
+         try
+         {
+            datasource = (DataSource) new InitialContext().lookup(jndiName);
+            
+            getLogger().debug("DataSource found at " + jndiName);
+         }
+         catch (NamingException e)
+         {
+            throw new IllegalStateException("Caught NamingException looking up DataSource at " + jndiName + " -- " + e
+                  .getLocalizedMessage());
+         }
+      }
+      else
+      {
+         datasource = injecteddatasource;
+      }
+      
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DataSourcePersistentStore.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DriverManagerPersistentStore.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DriverManagerPersistentStore.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DriverManagerPersistentStore.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,191 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Properties;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class DriverManagerPersistentStore extends RDBMSStoreBase
+{
+   
+   private static final String storeName = DriverManagerPersistentStore.class.getSimpleName();
+   /**
+       * The descriptive information about this implementation.
+       */
+   private static final String info = storeName + "/1.0";
+
+   // ------------------------------------------------------ Instance Fields
+
+   /**
+    * Connection string to use when connecting to the DB.
+    */
+   private String connectionURL = null;
+
+   private Lock lock = new ReentrantLock();
+   
+   /**
+    * The database connection.
+    */
+   private volatile Connection dbConnection = null;
+
+   /**
+    * Instance of the JDBC Driver class we use as a connection factory.
+    */
+   private Driver driver = null;
+
+   /**
+    * Driver to use.
+    */
+   private String driverName = null;
+
+   // ------------------------------------------------------------ Properties
+   
+   public String getStoreName()
+   {
+      return storeName;
+   }
+   
+   public String getConnectionURL()
+   {
+      return connectionURL;
+   }
+
+   public void setConnectionURL(String connectionURL)
+   {
+      this.connectionURL = connectionURL;
+   }
+
+   public String getDriverName()
+   {
+      return driverName;
+   }
+
+   public void setDriverName(String driverName)
+   {
+      this.driverName = driverName;
+   }
+
+   @Override
+   protected Connection getConnection() throws SQLException
+   {
+      try
+      {
+         lock.lockInterruptibly();
+      }
+      catch (InterruptedException e)
+      {
+         Thread.currentThread().interrupt();
+         throw new RuntimeException(sm.getString(getStoreName() + ".InterruptedException"), e);
+      }
+      
+      // Do nothing if there is a database connection already open
+      if (dbConnection == null)
+      {
+         open();
+      }
+      
+      return dbConnection;
+   }
+
+   @Override
+   protected void cleanup(Connection conn, ResultSet resultSet, boolean rollback)
+   {
+      this.dbConnection = null;
+      super.cleanup(conn, resultSet, rollback);
+   }
+
+   @Override
+   protected void releaseConnection(Connection dbConnection)
+   {
+      lock.unlock();
+   }
+
+   @Override
+   public String getInfo()
+   {
+      return info;
+   }
+
+   @Override
+   protected void startStore()
+   {
+      try
+      {
+         Class<?> clazz = Class.forName(driverName);
+         driver = (Driver) clazz.newInstance();
+      }
+      catch (ClassNotFoundException ex)
+      {
+         getLogger().error(
+               sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", ex.toString()));
+      }
+      catch (InstantiationException ex)
+      {
+         getLogger().error(
+               sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", ex.toString()));
+      }
+      catch (IllegalAccessException ex)
+      {
+         getLogger().error(
+               sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", ex.toString()));
+      }
+      
+      try
+      {
+         lock.lockInterruptibly();
+      }
+      catch (InterruptedException e)
+      {
+         Thread.currentThread().interrupt();
+         throw new RuntimeException(sm.getString(getStoreName() + ".startStoreInterruptedException", e.toString()));
+      }
+      
+      try
+      {
+         open();
+      }
+      catch (SQLException e)
+      {
+         throw new RuntimeException(sm.getString(getStoreName() + ".startStoreSqlException", e.toString()));
+      }
+      finally
+      {
+         lock.unlock();
+      }
+
+   }
+   
+   private Connection open() throws SQLException {
+
+      synchronized (this)
+      {
+         // Double-checked locking is ok since dbConnection is volatile
+         if (dbConnection != null)
+            return (dbConnection);
+         
+         // Open a new connection
+         Properties props = new Properties();
+         if (getConnectionName() != null)
+             props.put("user", getConnectionName());
+         if (getConnectionPassword() != null)
+             props.put("password", getConnectionPassword());
+         dbConnection = driver.connect(connectionURL, props);
+         dbConnection.setAutoCommit(true);
+         return (dbConnection);
+      }
+  }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/DriverManagerPersistentStore.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/ExtendedDistributedCacheManager.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/ExtendedDistributedCacheManager.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/ExtendedDistributedCacheManager.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,23 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManager;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ * Temporary extension to DistributedCacheManager to expose some further 
+ * session information.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public interface ExtendedDistributedCacheManager<T extends OutgoingDistributableSessionData> 
+      extends DistributedCacheManager<T>
+{
+   Integer getSessionVersion(String realId);
+   
+   Long getSessionTimestamp(String realId);
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/ExtendedDistributedCacheManager.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/IncomingDistributableSessionDataImpl.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/IncomingDistributableSessionDataImpl.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/IncomingDistributableSessionDataImpl.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,107 @@
+/*
+ * 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.web.tomcat.service.session.persistent;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
+
+/**
+ * Base implementation of {@link DistributableSessionData}.
+ * 
+ * @author Brian Stansberry
+ */
+public class IncomingDistributableSessionDataImpl implements IncomingDistributableSessionData
+{
+   private final int version;
+   private final long timestamp;
+   private final DistributableSessionMetadata metadata;
+   private final Map<String, Object> attributes;
+   
+   public IncomingDistributableSessionDataImpl(Integer version, Long timestamp, 
+                                              DistributableSessionMetadata metadata,
+                                              Map<String, Object> attributes)
+   {
+      if (version == null)
+         throw new IllegalStateException("version is null");
+      if (timestamp == null)
+         throw new IllegalStateException("timestamp is null");
+      if (metadata == null)
+         throw new IllegalStateException("metadata is null");
+      
+      this.version = version.intValue();
+      this.timestamp = timestamp.longValue();
+      this.metadata = metadata;
+      this.attributes = attributes;
+   }
+   
+   public IncomingDistributableSessionDataImpl(AtomicInteger version, AtomicLong timestamp, 
+                                              DistributableSessionMetadata metadata,
+                                              Map<String, Object> attributes)
+   {
+      if (version == null)
+         throw new IllegalStateException("version is null");
+      if (timestamp == null)
+         throw new IllegalStateException("timestamp is null");
+      if (metadata == null)
+         throw new IllegalStateException("metadata is null");
+      
+      this.version = version.get();
+      this.timestamp = timestamp.get();
+      this.metadata = metadata;
+      this.attributes = attributes;
+   }
+
+   public boolean providesSessionAttributes()
+   {
+      return attributes != null;
+   }
+
+   public Map<String, Object> getSessionAttributes()
+   {
+      if (attributes == null)
+      {
+         throw new IllegalStateException("Not configured to provide session attributes");
+      }
+      return attributes;
+   }   
+   
+   public DistributableSessionMetadata getMetadata()
+   {
+      return metadata;
+   }
+
+   public long getTimestamp()
+   {
+      return timestamp;
+   }
+
+   public int getVersion()
+   {
+      return version;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/IncomingDistributableSessionDataImpl.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStore.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStore.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStore.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,29 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import java.util.Set;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public interface PersistentStore
+{
+   Set<String> getSessionIds();
+   IncomingDistributableSessionData getSessionData(String realId, boolean includeAttributes);
+   Long getSessionTimestamp(String realId);
+   Integer getSessionVersion(String realId);
+   void storeSessionData(OutgoingSessionGranularitySessionData sessionData);
+   void remove(String id);
+   void processExpires();
+   void start();
+   void stop();
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStore.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManager.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManager.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManager.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,278 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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.web.tomcat.service.session.persistent;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.BatchingManager;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PersistentStoreDistributedCacheManager
+      implements ExtendedDistributedCacheManager<OutgoingSessionGranularitySessionData>
+{   
+   private static final BatchingManager BATCH_MGR = new NoOpBatchingManager();
+   
+   private final PersistentStore store;
+   
+   /**
+    * 
+    */
+   public PersistentStoreDistributedCacheManager(PersistentStore store)
+   {
+      if (store == null)
+      {
+         throw new IllegalArgumentException("Null store");
+      }
+      this.store = store;
+   }
+   
+   public BatchingManager getBatchingManager()
+   {
+      return BATCH_MGR;
+   }
+
+   public boolean isPassivationEnabled()
+   {
+      return true;
+   }
+
+   public void evictSession(String realId, String dataOwner)
+   {
+      // no-op -- we don't keep anything in memory
+   }
+
+   public void evictSession(String realId)
+   {
+      // no-op -- we don't keep anything in memory
+   }
+
+   public IncomingDistributableSessionData getSessionData(String realId, boolean initialLoad)
+   {
+      return getSessionData(realId, null, true);
+   }
+
+   public IncomingDistributableSessionData getSessionData(String realId, String dataOwner, boolean includeAttributes)
+   {
+      return store.getSessionData(realId, includeAttributes);
+   }
+
+   public Map<String, String> getSessionIds()
+   {
+      Map<String, String> result = new HashMap<String, String>();
+      Set<String> keys = store.getSessionIds();
+      if (keys != null)
+      {
+         for (String key : keys)
+         {
+            result.put(key, null);
+         }
+      }
+      
+      return result;
+   }
+    
+
+   public void removeSession(String realId)
+   {
+      store.remove(realId);
+   }
+
+   public void removeSessionLocal(String realId, String dataOwner)
+   {
+      removeSessionLocal(realId);
+   }
+
+   public void removeSessionLocal(String realId)
+   {
+      // Just remove it
+      store.remove(realId);
+   }
+
+   public void sessionCreated(String realId)
+   {
+      // no-op
+   }
+
+   public Long getSessionTimestamp(String realId)
+   {
+      return store.getSessionTimestamp(realId);
+   }
+
+   public Integer getSessionVersion(String realId)
+   {
+      return store.getSessionVersion(realId);
+   }
+
+   public void start()
+   {
+      store.start();            
+   }
+
+   public void stop()
+   {
+      store.stop();       
+   }
+
+   public void storeSessionData(OutgoingSessionGranularitySessionData sessionData)
+   {
+      store.storeSessionData(sessionData);    
+   } 
+
+   public boolean getSupportsAttributeOperations()
+   {
+      return false;
+   }
+
+   public Object getAttribute(String realId, String key)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+
+   public Set<String> getAttributeKeys(String realId)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+
+   public Map<String, Object> getAttributes(String realId)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+
+   public void putAttribute(String realId, Map<String, Object> map)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+
+   public void putAttribute(String realId, String key, Object value)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+
+   public Object removeAttribute(String realId, String key)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+
+   public void removeAttributeLocal(String realId, String key)
+   {
+      throw new UnsupportedOperationException("Attribute operations not supported " +
+            "with ReplicationGranularity " + ReplicationGranularity.SESSION);
+   }
+   
+   public static class NoOpBatchingManager implements BatchingManager
+   {
+      public boolean isBatchInProgress() throws Exception
+      {
+         return false;
+      }
+
+      public void startBatch() throws Exception
+      {
+         // no-op
+      }
+
+      public void endBatch()
+      {
+         // no-op
+      }
+
+      public void setBatchRollbackOnly() throws Exception
+      {
+         // no-op
+      }
+
+   }
+   
+   public static class IncomingDistributableSessionDataImpl implements IncomingDistributableSessionData
+   {
+      private final int version;
+      private final long timestamp;
+      private final DistributableSessionMetadata metadata;
+      private final Map<String, Object> attributes;
+      
+      public IncomingDistributableSessionDataImpl(Integer version, Long timestamp, 
+                                                 DistributableSessionMetadata metadata,
+                                                 Map<String, Object> attributes)
+      {
+         if (version == null)
+            throw new IllegalStateException("version is null");
+         if (timestamp == null)
+            throw new IllegalStateException("timestamp is null");
+         if (metadata == null)
+            throw new IllegalStateException("metadata is null");
+         
+         this.version = version.intValue();
+         this.timestamp = timestamp.longValue();
+         this.metadata = metadata;
+         this.attributes = attributes;
+      }
+
+      public boolean providesSessionAttributes()
+      {
+         return attributes != null;
+      }
+
+      public Map<String, Object> getSessionAttributes()
+      {
+         if (attributes == null)
+         {
+            throw new IllegalStateException("Not configured to provide session attributes");
+         }
+         return attributes;
+      }   
+      
+      public DistributableSessionMetadata getMetadata()
+      {
+         return metadata;
+      }
+
+      public long getTimestamp()
+      {
+         return timestamp;
+      }
+
+      public int getVersion()
+      {
+         return version;
+      }
+      
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManager.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManagerFactory.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManagerFactory.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManagerFactory.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,42 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import org.jboss.web.tomcat.service.session.distributedcache.spi.ClusteringNotSupportedException;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManager;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManagerFactory;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.LocalDistributableSessionManager;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PersistentStoreDistributedCacheManagerFactory implements DistributedCacheManagerFactory
+{
+   private final PersistentStore store;
+   
+   /**
+    * 
+    */
+   public PersistentStoreDistributedCacheManagerFactory(PersistentStore store)
+   {
+      if (store == null)
+      {
+         throw new IllegalArgumentException("Null store");
+      }
+      this.store = store;
+   }
+
+   @SuppressWarnings("unchecked")
+   public <T extends OutgoingDistributableSessionData> DistributedCacheManager<T> getDistributedCacheManager(
+         LocalDistributableSessionManager localManager) throws ClusteringNotSupportedException
+   {
+      return (DistributedCacheManager<T>) new PersistentStoreDistributedCacheManager(store);
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/PersistentStoreDistributedCacheManagerFactory.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/RDBMSStoreBase.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/RDBMSStoreBase.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/RDBMSStoreBase.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,1719 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.catalina.session.Constants;
+import org.apache.catalina.util.StringManager;
+import org.jboss.ha.framework.server.SimpleCachableMarshalledValue;
+import org.jboss.logging.Logger;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.IncomingDistributableSessionData;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingSessionGranularitySessionData;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.SessionSerializationFactory;
+
+/**
+ * Abstract superclass for {@link PersistentStore} implementations that store in a
+ * relational database.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public abstract class RDBMSStoreBase implements PersistentStore
+{
+   private static final Logger LOG = Logger.getLogger(RDBMSStoreBase.class);
+
+   public static final String DEFAULT_TABLE = "httpsessions";
+   public static final String DEFAULT_APP_COL = "app";
+   public static final String DEFAULT_ID_COL = "id";
+   public static final String DEFAULT_FULLID_COL = "fullid";
+   public static final String DEFAULT_ATTRIBUTE_COL = "attributes";
+   public static final String DEFAULT_METADATA_COL = "metadata";
+   public static final String DEFAULT_ISNEW_COL = "isnew";
+   public static final String DEFAULT_ISVALID_COL = "valid";
+   public static final String DEFAULT_CREATION_TIME_COL = "creationtime";
+   public static final String DEFAULT_LAST_ACCESSED_COL = "lastaccess";
+   public static final String DEFAULT_MAX_INACTIVE_COL = "maxinactive";
+   public static final String DEFAULT_VERSION_COL = "version";
+   
+   public static final int DEFAULT_CLEANUP_INTERVAL = 4 * 60 * 60;
+   
+   // --------------------------------------------------------- Instance Fields
+
+   /** Any inject logger */
+   private Logger logger = null;
+   
+   /**
+    * Has this component been started yet?
+    */
+   private boolean started = false;
+
+   /**
+    * The string manager for this package.
+    */
+   protected final StringManager sm = StringManager.getManager(Constants.Package);
+
+   /**
+    * Context name associated with this Store
+    */
+   private String name = null;
+   
+   /**
+    * How often to execute the processExpires cleanup
+    */
+   private int cleanupInterval = DEFAULT_CLEANUP_INTERVAL;
+   
+   /** When we last executed the processExpires cleanup */
+   private long lastCleanup = 0;
+
+   /**
+    * The connection username to use when trying to connect to the database.
+    */
+   private String connectionName = null;
+
+   /**
+    * The connection URL to use when trying to connect to the database.
+    */
+   private String connectionPassword = null;
+
+   /**
+    * Table to use.
+    */
+   private String sessionTable = DEFAULT_TABLE;
+
+   /**
+    * Column to use for /Engine/Host/Context name
+    */
+   private String sessionAppCol = DEFAULT_APP_COL;
+
+   /**
+    * Id column to use.
+    */
+   private String sessionIdCol = DEFAULT_ID_COL;
+
+   /**
+    * Full Id (e.g. including jvmRoute) column to use.
+    */
+   private String sessionFullIdCol = DEFAULT_FULLID_COL;
+
+   /**
+    * Creation time column to use
+    */
+   private String sessionCreationTimeCol = DEFAULT_CREATION_TIME_COL;
+
+   /**
+    * Max Inactive column to use.
+    */
+   private String sessionMaxInactiveCol = DEFAULT_MAX_INACTIVE_COL;
+
+   /**
+    * Version column to use.
+    */
+   private String sessionVersionCol = DEFAULT_VERSION_COL;
+
+   /**
+    * Last Accessed column to use.
+    */
+   private String sessionLastAccessedCol = DEFAULT_LAST_ACCESSED_COL;
+
+   /**
+    * Is New column to use
+    */
+   private String sessionNewCol = DEFAULT_ISNEW_COL;
+
+   /**
+    * Is Valid column to use.
+    */
+   private String sessionValidCol = DEFAULT_ISVALID_COL;
+
+   /**
+    * Column to use for misc metadata.
+    */
+   private String sessionMetadataCol = DEFAULT_METADATA_COL;
+
+   /**
+    * Attribute column to use.
+    */
+   private String sessionAttributeCol = DEFAULT_ATTRIBUTE_COL;
+
+   private String clearSql;
+
+   private String sizeSql;
+
+   private String insertSql;
+
+   private String fullUpdateSql;
+
+   private String keysSql;
+
+   private String fullLoadSql;
+
+   private String partialLoadSql;
+
+   private String removeSql;
+
+   private String versionSql;
+
+   private String timestampSql;
+
+   private final Map<Connection, Set<Statement>> statementsByConnection = new ConcurrentHashMap<Connection, Set<Statement>>();
+
+   private String simpleUpdateSql;
+
+   private String attributeUpdateSql;
+
+   private String metadataUpdateSql;
+
+   private String cleanupSql;
+   
+   private final byte[] emptyAttributes;
+
+   // -------------------------------------------------------- Constructors
+   
+   protected RDBMSStoreBase()
+   {
+      try
+      {
+         @SuppressWarnings("unchecked")
+         Object empty = new SimpleCachableMarshalledValue(new HashMap());
+         ByteArrayOutputStream baos = new ByteArrayOutputStream();
+         ObjectOutputStream oos = new ObjectOutputStream(baos);
+         oos.writeObject(empty);
+         oos.close();
+         emptyAttributes = baos.toByteArray();
+      }
+      catch (IOException e)
+      {
+         throw new RuntimeException("Cannot serialize simple HashMap");
+      }      
+   }
+   
+   // ------------------------------------------------------------- Properties
+
+   /**
+    * Return the name for this Store, used for logging.
+    */
+   public abstract String getStoreName();
+
+   /**
+    * Return the info for this Store.
+    */
+   public abstract String getInfo();
+
+   /**
+    * Return the name for this instance (built from container name)
+    */
+   public String getName()
+   {
+      if (name == null)
+      {
+         throw new IllegalStateException("Must configure a name for PersistentStore");
+      }
+      return name;
+   }
+   
+   public void setName(String name)
+   {
+      this.name = name;
+   }
+
+   /**
+    * Return the username to use to connect to the database.
+    *
+    */
+   public String getConnectionName()
+   {
+      return (this.connectionName);
+   }
+
+   /**
+    * Set the username to use to connect to the database.
+    *
+    * @param connectionName Username
+    */
+   public void setConnectionName(String connectionName)
+   {
+      this.connectionName = connectionName;
+   }
+
+   /**
+    * Return the password to use to connect to the database.
+    *
+    */
+   public String getConnectionPassword()
+   {
+      return (this.connectionPassword);
+   }
+
+   /**
+    * Set the password to use to connect to the database.
+    *
+    * @param connectionPassword User password
+    */
+   public void setConnectionPassword(String connectionPassword)
+   {
+      this.connectionPassword = connectionPassword;
+   }
+
+   /**
+    * Set the table for this Store.
+    *
+    * @param sessionTable The new table
+    */
+   public void setSessionTable(String sessionTable)
+   {
+      this.sessionTable = sessionTable;
+   }
+
+   /**
+    * Return the table for this Store.
+    */
+   public String getSessionTable()
+   {
+      return (this.sessionTable);
+   }
+
+   /**
+    * Set the App column for the table.
+    *
+    * @param sessionAppCol the column name
+    */
+   public void setSessionAppCol(String sessionAppCol)
+   {
+      this.sessionAppCol = sessionAppCol;
+   }
+
+   /**
+    * Return the web application name column for the table.
+    */
+   public String getSessionAppCol()
+   {
+      return (this.sessionAppCol);
+   }
+
+   /**
+    * Return the name of the session id column for the table. This is where the 
+    * core, immutable part of the session id is stored.
+    */
+   public String getSessionIdCol()
+   {
+      return (this.sessionIdCol);
+   }
+
+   /**
+    * Set the name of the session id column for the table. This is where the 
+    * core, immutable part of the session id is stored.
+    *
+    * @param sessionIdCol the column name
+    */
+   public void setSessionIdCol(String sessionIdCol)
+   {
+      this.sessionIdCol = sessionIdCol;
+   }
+
+   /**
+    * Returns the name of the full session id column for the table. This is where
+    * the full id including any mutable element (e.g. a jvmRoute) that is added 
+    * to the {@link #getSessionIdCol() core session id} is stored.
+    */
+   public String getSessionFullIdCol()
+   {
+      return (this.sessionFullIdCol);
+   }
+
+   /**
+    * Set the name of the full session id column for the table. This is where
+    * the full id including any mutable element (e.g. a jvmRoute) that is added 
+    * to the {@link #getSessionIdCol() core session id} is stored.
+    *
+    * @param sessionFullIdCol the column name
+    */
+   public void setSessionFullIdCol(String sessionFullIdCol)
+   {
+      this.sessionFullIdCol = sessionFullIdCol;
+   }
+
+   /**
+    * Gets the name of the column where the session creation time is stored.
+    * 
+    * @return the column name
+    */
+   public String getSessionCreationTimeCol()
+   {
+      return (this.sessionCreationTimeCol);
+   }
+
+   /**
+    * Sets the name of the column where the session creation time is stored.
+    * 
+    * param sessionCreationTimeCol the column name
+    */
+   public void setSessionCreationTimeCol(String sessionCreationTimeCol)
+   {
+      this.sessionCreationTimeCol = sessionCreationTimeCol;
+   }
+
+   /**
+    * Return the Max Inactive column
+    */
+   public String getSessionMaxInactiveCol()
+   {
+      return (this.sessionMaxInactiveCol);
+   }
+
+   /**
+    * Set the Max Inactive column for the table
+    *
+    * @param sessionMaxInactiveCol The column name
+    */
+   public void setSessionMaxInactiveCol(String sessionMaxInactiveCol)
+   {
+      this.sessionMaxInactiveCol = sessionMaxInactiveCol;
+   }
+
+   /**
+    * Gets the name of "session is new" marker column
+    * 
+    * @return the column name
+    */
+   public String getSessionNewCol()
+   {
+      return (this.sessionNewCol);
+   }
+
+   /**
+    * Sets the name of "session is new" marker column
+    * 
+    * @param sessionNewCol the column name
+    */
+   public void setSessionNewCol(String sessionNewCol)
+   {
+      this.sessionNewCol = sessionNewCol;
+   }
+
+   /**
+    * Return the name of the session version column
+    */
+   public String getSessionVersionCol()
+   {
+      return (this.sessionVersionCol);
+   }
+
+   /**
+    * Set the name of the session version column for the table
+    *
+    * @param sessionVersionCol The column name
+    */
+   public void setSessionVersionCol(String sessionVersionCol)
+   {
+      this.sessionVersionCol = sessionVersionCol;
+   }
+
+   /**
+    * Return the name of the session last access timestamp column
+    */
+   public String getSessionLastAccessedCol()
+   {
+      return (this.sessionLastAccessedCol);
+   }
+
+   /**
+    * Set the name of the session last access timestamp column for the table
+    *
+    * @param sessionLastAccessedCol The column name
+    */
+   public void setSessionLastAccessedCol(String sessionLastAccessedCol)
+   {
+      this.sessionLastAccessedCol = sessionLastAccessedCol;
+   }
+
+   /**
+    * Return the Iname of the session validity marker column
+    */
+   public String getSessionValidCol()
+   {
+      return (this.sessionValidCol);
+   }
+
+   /**
+    * Set the name of the session validity marker column for the table
+    *
+    * @param sessionValidCol The column name
+    */
+   public void setSessionValidCol(String sessionValidCol)
+   {
+      this.sessionValidCol = sessionValidCol;
+   }
+
+   /**
+    * Return the name of the misc misc metadata storage column
+    */
+   public String getSessionMetadataCol()
+   {
+      return (this.sessionMetadataCol);
+   }
+
+   /**
+    * Set the name of the misc metadata storage column for the table
+    *
+    * @param sessionValidCol The column name
+    */
+   public void setSessionMetadataCol(String sessionMetadataCol)
+   {
+      this.sessionMetadataCol = sessionMetadataCol;
+   }
+
+   /**
+    * Return the attribute storage column for the table
+    */
+   public String getSessionAttributeCol()
+   {
+      return (this.sessionAttributeCol);
+   }
+
+   /**
+    * Set the attribute storage column for the table
+    *
+    * @param sessionAttributeCol the column name
+    */
+   public void setSessionAttributeCol(String sessionAttributeCol)
+   {
+      this.sessionAttributeCol = sessionAttributeCol;
+   }
+
+   public int getCleanupInterval()
+   {
+      return cleanupInterval;
+   }
+
+   public void setCleanupInterval(int cleanupInterval)
+   {
+      this.cleanupInterval = cleanupInterval;
+   }
+   
+   public boolean isStarted()
+   {
+      return started;
+   }
+
+   // --------------------------------------------------------- Public Methods
+
+   
+   // -------------------------------------------------------  PersistentStore
+
+   public void clear()
+   {
+      RuntimeException exception = null;
+      int numberOfTries = 2;
+      while (numberOfTries-- > 0)
+      {
+         Connection _conn = safeGetConnection();
+         boolean success = false;
+         try
+         {
+            PreparedStatement preparedClearSql = prepareStatement(_conn, getClearSql());
+            preparedClearSql.setString(1, getName());
+            preparedClearSql.execute();
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e));
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, null, true);
+               }
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+   }
+
+   public int getSize()
+   {
+      int size = 0;
+      ResultSet rst = null;
+      RuntimeException exception = null;
+      
+      int numberOfTries = 2;
+      while (numberOfTries-- > 0)
+      {
+         Connection _conn = safeGetConnection();
+         boolean success = false;
+         try
+         {
+            PreparedStatement preparedSizeSql = prepareStatement(_conn, getSizeSql());
+            preparedSizeSql.setString(1, getName());
+            rst = preparedSizeSql.executeQuery();
+            if (rst.next())
+            {
+               size = rst.getInt(1);
+            }
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e), e);
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, rst, true);
+               }
+               else if (rst != null)
+               {
+                  rst.close();
+               }
+            }
+            catch (SQLException e)
+            {
+               ;
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+      
+      return (size);
+   }
+
+   public Set<String> getSessionIds()
+   {
+      ResultSet rst = null;
+      Set<String> keys = null;
+      RuntimeException exception = null;
+      int numberOfTries = 2;
+      while (numberOfTries-- > 0)
+      {
+         Connection _conn = safeGetConnection();
+         boolean success = true;
+         try
+         {
+            PreparedStatement preparedKeysSql = prepareStatement(_conn, getKeysSql());
+            preparedKeysSql.setString(1, getName());
+            rst = preparedKeysSql.executeQuery();
+            keys = new HashSet<String>();
+            if (rst != null)
+            {
+               while (rst.next())
+               {
+                  keys.add(rst.getString(1));
+               }
+            }
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e));
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, rst, true);
+               }
+               else if (rst != null)
+               {
+                  rst.close();
+               }
+            }
+            catch (SQLException e)
+            {
+               ;
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+
+      return (keys);
+   }
+
+   public IncomingDistributableSessionData getSessionData(String realId, boolean includeAttributes)
+   {
+      ResultSet rst = null;
+      IncomingDistributableSessionData incomingSession = null;
+      ObjectInputStream attributes_ois = null;
+
+      RuntimeException exception = null;
+      
+      int numberOfTries = 2;
+      while (numberOfTries-- > 0)
+      {
+         Connection _conn = safeGetConnection();
+         boolean success = false;
+         try
+         {
+            String sql = includeAttributes ? getFullLoadSql() : getPartialLoadSql();
+            PreparedStatement preparedLoadSql = prepareStatement(_conn, sql);
+            preparedLoadSql.setString(1, realId);
+            preparedLoadSql.setString(2, getName());
+            rst = preparedLoadSql.executeQuery();
+            if (rst.next())
+            {
+               if (getLogger().isTraceEnabled())
+               {
+                  getLogger().trace(sm.getString(getStoreName() + ".loading", realId, sessionTable));
+               }
+
+               DistributableSessionMetadata metadata = new DistributableSessionMetadata();
+
+               metadata.setId(rst.getString(1));
+               metadata.setCreationTime(rst.getLong(2));
+               String isNew = rst.getString(3);
+               metadata.setNew("1".equals(isNew));
+               metadata.setMaxInactiveInterval(rst.getInt(4));
+               String valid = rst.getString(7);
+               // FIXME experiment
+//               metadata.setValid("1".equals(valid));
+               metadata.setValid(true);
+
+               Integer version = Integer.valueOf(rst.getInt(5));
+               Long timestamp = Long.valueOf(rst.getLong(6));
+
+               Map<String, Object> attributes = null;
+               if (includeAttributes)
+               {
+                  BufferedInputStream attributes_bis = new BufferedInputStream(rst.getBinaryStream(8));
+                  attributes_ois = new ObjectInputStream(attributes_bis);                  
+                  SimpleCachableMarshalledValue mv = (SimpleCachableMarshalledValue) attributes_ois.readObject();
+                  mv.setObjectStreamSource(SessionSerializationFactory.getObjectStreamSource());
+
+                  attributes = uncheckedCast(mv.get());
+               }
+
+               incomingSession = new IncomingDistributableSessionDataImpl(version, timestamp, metadata, attributes);
+
+            }
+            else if (getLogger().isTraceEnabled())
+            {
+               getLogger().trace(getStoreName() + ": No persisted data object found");
+            }
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e));
+            }
+         }
+         catch (IOException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".IOException", e), e);
+            }
+         }
+         catch (ClassNotFoundException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".ClassNotFoundException", e), e);
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, rst, true);
+               }
+               else if (rst != null)
+               {
+                  rst.close();
+               }
+
+               if (attributes_ois != null)
+               {
+                  try
+                  {
+                     attributes_ois.close();
+                  }
+                  catch (IOException e)
+                  {
+                     ;
+                  }
+               }
+            }
+            catch (SQLException e)
+            {
+               ;
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+
+      return (incomingSession);
+   }
+
+   public void remove(String id)
+   {
+      if (getLogger().isTraceEnabled())
+      {
+         getLogger().trace(sm.getString(getStoreName() + ".removing", id, sessionTable));
+      }
+      
+      RuntimeException exception = null;
+      int numberOfTries = 2;
+      while (numberOfTries-- > 0)
+      {
+         Connection _conn = safeGetConnection();
+         boolean success = false;
+         try
+         {
+            executeRemove(id, _conn);
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e));
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, null, true);
+               }
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+   }
+
+   public void storeSessionData(OutgoingSessionGranularitySessionData sessionData)
+   {
+      if (getLogger().isTraceEnabled())
+      {
+         getLogger().trace(
+               sm.getString(getStoreName() + ".saving", sessionData.getRealId(), sessionTable));
+      }
+      
+      RuntimeException exception = null;
+      ObjectOutputStream oos = null;
+      int numberOfTries = 2;
+      while (numberOfTries-- > 0)
+      {
+         boolean success = false;
+         Connection _conn = safeGetConnection();
+         if (_conn == null)
+         {
+            return;
+         }
+
+         try
+         {
+            byte[] obs = writeSessionAttributes(sessionData);
+
+            DistributableSessionMetadata metadata = sessionData.getMetadata();
+            if (metadata != null && metadata.isNew())
+            {
+               try
+               {
+                  executeInsert(sessionData, obs, _conn);
+               }
+               catch (SQLException e)
+               {                  
+                  // See if this is due to pre-existing record
+                  if (getLogger().isTraceEnabled())
+                  {
+                     getLogger().trace(sm.getString(getStoreName() + ".insertSQLException", e));
+                  }
+                  if (executeGetSessionVersion(_conn, sessionData.getRealId()) != null)
+                  {
+                     executeUpdate(sessionData, obs, _conn);
+                  }
+                  else
+                  {
+                     throw e;
+                  }
+               }
+            }
+            else
+            {
+               int count = executeUpdate(sessionData, obs, _conn);
+               if (count < 1)
+               {
+                  // For whatever reason this doesn't exist                  
+                  if (metadata != null && obs != null)
+                  {
+                     executeInsert(sessionData, obs, _conn);
+                  }
+                  else
+                  {
+                     // Hmm, we don't have enough data for a full insert
+                     throw new IllegalStateException("Cannot insert session " + maskId(sessionData.getRealId()) + " as session metadata is not available");
+                  }
+               }
+            }
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException("storeSessionData(): Caught exception storing session " +  (maskId(sessionData.getRealId()) + " -- " + e.getLocalizedMessage()), e);
+            }
+         }
+         catch (IOException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".IOException", e), e);
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, null, true);
+               }
+
+               if (oos != null)
+               {
+                  try
+                  {
+                     oos.close();
+                  }
+                  catch (IOException ignored)
+                  {
+                     ;
+                  }
+               }
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+   }   
+   
+   private static String maskId(String realId)
+   {
+      if (realId == null)
+      {
+         return null;
+      }
+      else
+      {
+         int length = realId.length();
+         if (length <= 8)
+         {
+            return realId;
+         }
+         StringBuilder sb = new StringBuilder(realId.substring(0, 2));
+         sb.append("****");
+         sb.append(sb.substring(length - 6, length));
+         return sb.toString();
+      }
+   }
+
+   public Long getSessionTimestamp(String realId)
+   {
+      ResultSet rst = null;
+      Long result = null;
+      RuntimeException exception = null;
+      int numberOfTries = 2;   
+      while (numberOfTries-- > 0)
+      {
+         boolean success = false;
+         Connection _conn = safeGetConnection();
+         try
+         {
+            PreparedStatement preparedTimestampSql = prepareStatement(_conn, getTimestampSql());
+            preparedTimestampSql.setString(1, realId);
+            preparedTimestampSql.setString(2, getName());
+            rst = preparedTimestampSql.executeQuery();
+            if (rst.next())
+            {
+               result = Long.valueOf(rst.getLong(1));
+            }
+
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e));
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, rst, true);
+               }
+               else if (rst != null)
+               {
+                  try
+                  {
+                     rst.close();
+                  }
+                  catch (SQLException e)
+                  {
+                     ;
+                  }
+               }
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+      
+      return result;
+   }
+
+   public Integer getSessionVersion(String realId)
+   {
+      
+      Integer result = null;
+      RuntimeException exception = null;
+      int numberOfTries = 2;   
+      while (numberOfTries-- > 0)
+      {
+         boolean success = false;
+         Connection _conn = safeGetConnection();   
+         try
+         {
+            result = executeGetSessionVersion(_conn, realId);
+            _conn.commit();
+            success = true;
+            exception = null;
+            break;
+         }
+         catch (SQLException e)
+         {
+            if (exception == null)
+            {
+               exception = new RuntimeException(sm.getString(getStoreName() + ".SQLException", e));
+            }
+         }
+         catch (RuntimeException e)
+         {
+            if (exception == null)
+            {
+               exception = e;
+            }
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+//                  cleanup(_conn, rst, true);
+                  cleanup(_conn, null, true);
+               }
+//               else if (rst != null)
+//               {
+//                  try
+//                  {
+//                     rst.close();
+//                  }
+//                  catch (SQLException e)
+//                  {
+//                     ;
+//                  }
+//               }
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }
+      }
+      
+      if (exception != null)
+      {
+         throw exception;
+      }
+      
+      return result;
+   }
+
+   public void processExpires()
+   {
+      long now = System.currentTimeMillis();
+      long interval = cleanupInterval * 1000;
+      long earliest = now - interval;
+      if (earliest > lastCleanup)
+      {
+         Connection _conn = safeGetConnection();
+         boolean success = false;
+         try
+         {
+            PreparedStatement preparedCleanupSql = prepareStatement(_conn, getCleanupSql());
+            preparedCleanupSql.setString(1, getName());
+            preparedCleanupSql.setLong(2, earliest);
+            preparedCleanupSql.setLong(3, now);
+            preparedCleanupSql.execute();
+
+            _conn.commit();
+            lastCleanup = now;
+            success = true;
+         }
+         catch (SQLException e)
+         {
+            getLogger().error(sm.getString(getStoreName() + ".SQLException", e));            
+         }
+         catch (RuntimeException e)
+         {
+            getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); 
+         }
+         finally
+         {
+            try
+            {
+               if (!success)
+               {
+                  cleanup(_conn, null, true);
+               }
+            }
+            finally
+            {
+               releaseConnection(_conn);
+            }
+         }        
+      }
+   }
+
+   public void start()
+   {
+      // Validate and update our current component state
+      if (started)
+         throw new IllegalStateException(sm.getString(getStoreName() + ".alreadyStarted"));
+
+      getName();
+
+      createSql();
+
+      startStore();
+
+      started = true;
+   }
+
+   public void stop()
+   {
+      // Validate and update our current component state
+      if (!started)
+      {
+         throw new IllegalStateException(sm.getString(getStoreName() + ".notStarted"));
+      }
+
+      started = false;
+
+   }
+
+   // --------------------------------------------------------------  Protected
+
+   /** 
+    * Hook for subclasses to perform any needed startup work.
+    */
+   protected abstract void startStore();
+
+   /**
+    * Returns a connection. Calls to this method
+    * must be paired (typically via a try/finally block) with a call
+    * to {@link #releaseConnection(Connection)}.
+    * 
+    * @return the connection
+    * 
+    * @throws SQLException if a database access error occurs
+    * @throws RuntimeException if a connection could not be obtained
+    */
+   protected abstract Connection getConnection() throws SQLException;
+
+   /**
+    * Releases a connection obtained from {@link #getConnection()}.
+    * 
+    * @param conn the connection
+    */
+   protected abstract void releaseConnection(Connection conn);
+
+   /**
+    * Clean up a connection, any associated statements, and an associated
+    * result set.
+    * 
+    * @param conn the connection. Null is handled but isn't sensible
+    * @param resultSet the result set, which may be null
+    * @param rollback whether {@link Connection#rollback()} should be invoked on the connection
+    */
+   protected void cleanup(Connection conn, ResultSet resultSet, boolean rollback)
+   {
+      if (conn != null)
+      {
+         if (resultSet != null)
+         {
+            try
+            {
+               resultSet.close();
+            }
+            catch (SQLException e)
+            {
+               getLogger().error(sm.getString(getStoreName() + ".closeResultSet", e.toString())); // Just log it here
+            }
+         }
+
+         if (rollback)
+         {
+            try
+            {
+               conn.rollback();
+            }
+            catch (SQLException e)
+            {
+               if (getLogger().isTraceEnabled())
+               {
+                  getLogger().trace(sm.getString(getStoreName() + ".rollback", e.toString()));
+               }
+            }
+         }
+
+         Set<Statement> stmts = statementsByConnection.remove(conn);
+         if (stmts != null)
+         {
+            for (Statement stmt : stmts)
+            {
+               try
+               {
+                  stmt.close();
+               }
+               catch (Exception e)
+               {
+                  getLogger().debug(e.getLocalizedMessage());
+               }
+            }
+         }
+
+         // Close this database connection, and log any errors
+         try
+         {
+            conn.close();
+         }
+         catch (SQLException e)
+         {
+            getLogger().error(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here
+         }
+      }
+   }
+   
+   protected Logger getLogger()
+   {
+      return logger == null ? LOG : logger;
+   }
+
+   // ----------------------------------------------------------------  Private
+
+   /**
+    * Establishes the SQL strings returned by the various <code>getXyzSql()</code>
+    * methods.
+    */
+   private void createSql()
+   {
+      this.clearSql = "DELETE FROM " + getSessionTable() + " WHERE " + getSessionAppCol() + " = ?";
+
+      this.keysSql = "SELECT " + getSessionIdCol() + " FROM " + getSessionTable() + " WHERE " + getSessionAppCol()
+            + " = ?";
+      
+      this.sizeSql = "SELECT COUNT(" + getSessionIdCol() + ") " +
+      		"        FROM " + getSessionTable() + 
+      		        " WHERE " + getSessionAppCol() + " = ?";
+
+      this.fullLoadSql = "SELECT " + getSessionFullIdCol() + ", " + getSessionCreationTimeCol() + ", "
+            + getSessionNewCol() + ", " + getSessionMaxInactiveCol() + ", " + getSessionVersionCol() + ", "
+            + getSessionLastAccessedCol() + ", " + getSessionValidCol() + ", " + getSessionAttributeCol() + " FROM "
+            + getSessionTable() + " WHERE " + getSessionIdCol() + " = ? AND " + getSessionAppCol() + " = ?";
+
+      this.partialLoadSql = "SELECT " + getSessionFullIdCol() + ", " + getSessionCreationTimeCol() + ", "
+            + getSessionNewCol() + ", " + getSessionMaxInactiveCol() + ", " + getSessionVersionCol() + ", "
+            + getSessionLastAccessedCol() + ", " + getSessionValidCol() + " FROM " + getSessionTable() + " WHERE "
+            + getSessionIdCol() + " = ? AND " + getSessionAppCol() + " = ?";
+
+      this.removeSql = "DELETE FROM " + getSessionTable() + " WHERE " + getSessionIdCol() + " = ? AND "
+            + getSessionAppCol() + " = ?";
+
+      this.insertSql = "INSERT INTO " + getSessionTable() + " (" + getSessionAppCol() + ", " + getSessionIdCol() + ", "
+            + getSessionFullIdCol() + ", " + getSessionCreationTimeCol() + ", " + getSessionNewCol() + ", "
+            + getSessionMaxInactiveCol() + ", " + getSessionVersionCol() + ", " + getSessionLastAccessedCol() + ", "
+            + getSessionValidCol() + ", " + getSessionAttributeCol() + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+      this.simpleUpdateSql = "UPDATE " + getSessionTable() + " SET " + getSessionVersionCol() + " = ?, "
+            + getSessionLastAccessedCol() + " = ?" + " WHERE " + getSessionIdCol() + " = ? AND " + getSessionAppCol()
+            + " = ?";
+
+      this.attributeUpdateSql = "UPDATE " + getSessionTable() + " SET " + getSessionVersionCol() + " = ?, "
+            + getSessionLastAccessedCol() + " = ?, " + getSessionAttributeCol() + " = ?" + " WHERE "
+            + getSessionIdCol() + " = ? AND " + getSessionAppCol() + " = ?";
+
+      this.metadataUpdateSql = "UPDATE " + getSessionTable() + " SET " + getSessionVersionCol() + " = ?, "
+            + getSessionLastAccessedCol() + " = ?, " + getSessionFullIdCol() + " = ?, " + getSessionNewCol() + " = ?, "
+            + getSessionMaxInactiveCol() + " = ?, " + getSessionValidCol() + " = ?" + " WHERE " + getSessionIdCol()
+            + " = ? AND " + getSessionAppCol() + " = ?";
+
+      this.fullUpdateSql = "UPDATE " + getSessionTable() + " SET " + getSessionVersionCol() + " = ?, "
+            + getSessionLastAccessedCol() + " = ?, " + getSessionFullIdCol() + " = ?, " + getSessionNewCol() + " = ?, "
+            + getSessionMaxInactiveCol() + " = ?, " + getSessionValidCol() + " = ?, " + getSessionAttributeCol()
+            + " = ?" + " WHERE " + getSessionIdCol() + " = ? AND " + getSessionAppCol() + " = ?";
+
+      this.timestampSql = "SELECT " + getSessionLastAccessedCol() + " FROM " + getSessionTable() + " WHERE "
+            + getSessionIdCol() + " = ? AND " + getSessionAppCol() + " = ?";
+
+      this.versionSql = "SELECT " + getSessionVersionCol() + " FROM " + getSessionTable() + " WHERE "
+            + getSessionIdCol() + " = ? AND " + getSessionAppCol() + " = ?";
+      
+      this.cleanupSql = "DELETE FROM " + getSessionTable() + " WHERE " + getSessionAppCol() + " = ?" +
+                   " AND " + getSessionLastAccessedCol() + " < ? AND " + getSessionLastAccessedCol() + " < (? - " +
+                   getSessionMaxInactiveCol() + ")";
+   }
+
+   private void executeRemove(String id, Connection _conn) throws SQLException
+   {
+      PreparedStatement preparedRemoveSql = prepareStatement(_conn, getRemoveSql());
+      preparedRemoveSql.setString(1, id);
+      preparedRemoveSql.setString(2, getName());
+      preparedRemoveSql.execute();
+   }
+
+   private void executeInsert(OutgoingSessionGranularitySessionData session, byte[] obs, Connection conn)
+         throws SQLException, IOException
+   {
+      if (obs == null)
+      {
+         obs = this.emptyAttributes;
+      }
+
+      DistributableSessionMetadata metadata = session.getMetadata();
+      if (metadata == null)
+      {
+         throw new IllegalStateException(sm.getString(getStoreName() + ".insertMissingMetadataException"));
+      }
+
+      int size = obs.length;
+      ByteArrayInputStream bis = new ByteArrayInputStream(obs);
+      InputStream in = new BufferedInputStream(bis, size);
+
+      try
+      {
+         PreparedStatement preparedInsertSql = prepareStatement(conn, getInsertSql());
+         preparedInsertSql.setString(1, getName());
+         preparedInsertSql.setString(2, session.getRealId());
+         preparedInsertSql.setString(3, metadata.getId());
+         preparedInsertSql.setLong(4, metadata.getCreationTime());
+         preparedInsertSql.setString(5, metadata.isNew() ? "1" : "0");
+         preparedInsertSql.setInt(6, metadata.getMaxInactiveInterval());
+         preparedInsertSql.setInt(7, session.getVersion());
+         preparedInsertSql.setLong(8, session.getTimestamp());
+         preparedInsertSql.setString(9, metadata.isValid() ? "1" : "0");
+         preparedInsertSql.setBinaryStream(10, in, size);
+         preparedInsertSql.execute();
+      }
+      finally
+      {
+         in.close();
+      }
+   }
+
+   private int executeUpdate(OutgoingSessionGranularitySessionData session, byte[] obs, Connection conn)
+         throws SQLException, IOException
+   {
+      DistributableSessionMetadata metadata = session.getMetadata();
+      int size = obs == null ? -1 : obs.length;
+      InputStream in = null;
+      if (obs != null)
+      {
+         ByteArrayInputStream bis = new ByteArrayInputStream(obs);
+         in = new BufferedInputStream(bis, size);
+      }
+
+      try
+      {
+         PreparedStatement preparedUpdateSql = null;
+         int idParam = -1; // first parameter in the WHERE clause
+         if (metadata != null)
+         {
+            if (obs != null)
+            {
+               preparedUpdateSql = prepareStatement(conn, getFullUpdateSql());
+               preparedUpdateSql.setBinaryStream(7, in, size);
+               idParam = 8;
+            }
+            else
+            {
+               preparedUpdateSql = prepareStatement(conn, getMetadataUpdateSql());
+               idParam = 7;
+            }
+
+            preparedUpdateSql.setString(3, metadata.getId());
+            preparedUpdateSql.setString(4, metadata.isNew() ? "1" : "0");
+            preparedUpdateSql.setInt(5, metadata.getMaxInactiveInterval());
+            preparedUpdateSql.setString(6, metadata.isValid() ? "1" : "0");
+         }
+         else if (obs != null)
+         {
+            preparedUpdateSql = prepareStatement(conn, getAttributeUpdateSql());
+            preparedUpdateSql.setBinaryStream(3, in, size);
+            idParam = 4;
+         }
+         else
+         {
+            preparedUpdateSql = prepareStatement(conn, getSimpleUpdateSql());
+            idParam = 3;
+         }
+
+         // Add in the version and timestamp
+         preparedUpdateSql.setInt(1, session.getVersion());
+         preparedUpdateSql.setLong(2, session.getTimestamp());
+         // Add in the WHERE clause params
+         preparedUpdateSql.setString(idParam, session.getRealId());
+         preparedUpdateSql.setString(idParam + 1, getName());
+         int count = preparedUpdateSql.executeUpdate();
+
+         return count;
+      }
+      finally
+      {
+         if (in != null)
+         {
+            in.close();
+         }
+      }
+   }
+   
+   private Integer executeGetSessionVersion(Connection _conn, String realId) throws SQLException
+   {
+      PreparedStatement preparedTimestampSql = prepareStatement(_conn, getVersionSql());
+      preparedTimestampSql.setString(1, realId);
+      preparedTimestampSql.setString(2, getName());
+      ResultSet rst = null;
+      try
+      {
+         Integer result = null;
+         rst = preparedTimestampSql.executeQuery();
+         if (rst.next())
+         {
+            result = Integer.valueOf(rst.getInt(1));
+         }
+         return result;
+      }
+      finally
+      {
+         if (rst != null)
+         {
+            rst.close();
+         }
+      }
+   }
+
+   private String getCleanupSql()
+   {
+      return cleanupSql;
+   }
+
+   private String getClearSql()
+   {
+      return clearSql;
+   }
+
+   private String getInsertSql()
+   {
+      return insertSql;
+   }
+
+   private String getFullUpdateSql()
+   {
+      return fullUpdateSql;
+   }
+
+   private String getSimpleUpdateSql()
+   {
+      return simpleUpdateSql;
+   }
+
+   private String getMetadataUpdateSql()
+   {
+      return metadataUpdateSql;
+   }
+
+   private String getAttributeUpdateSql()
+   {
+      return attributeUpdateSql;
+   }
+
+   private String getKeysSql()
+   {
+      return keysSql;
+   }
+
+   private String getFullLoadSql()
+   {
+      return fullLoadSql;
+   }
+
+   private String getPartialLoadSql()
+   {
+      return this.partialLoadSql;
+   }
+
+   private String getRemoveSql()
+   {
+      return removeSql;
+   }
+
+   private String getSizeSql()
+   {
+      return sizeSql;
+   }
+
+   private String getVersionSql()
+   {
+      return versionSql;
+   }
+
+   private String getTimestampSql()
+   {
+      return timestampSql;
+   }
+
+   private Connection safeGetConnection()
+   {
+      try
+      {
+         return getConnection();
+      }
+      catch (SQLException e)
+      {
+         throw new RuntimeException(sm.getString(getStoreName() + ".getConnectionSqlException", e.toString()));
+      }      
+   }
+
+   private PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException
+   {
+      Set<Statement> stmts = statementsByConnection.get(conn);
+      if (stmts == null)
+      {
+         stmts = new HashSet<Statement>();
+         statementsByConnection.put(conn, stmts);
+      }
+      PreparedStatement stmt = conn.prepareStatement(sql);
+      stmts.add(stmt);
+      return stmt;
+   }
+
+   private byte[] writeSessionAttributes(OutgoingSessionGranularitySessionData session) throws IOException
+   {
+      Map<String, Object> attrs = session.getSessionAttributes();
+      if (attrs == null)
+      {
+         return null;
+      }
+
+      ObjectOutputStream oos = null;
+      ByteArrayOutputStream bos = null;
+
+      try
+      {
+         bos = new ByteArrayOutputStream();
+         oos = new ObjectOutputStream(new BufferedOutputStream(bos));
+
+         oos.writeObject(new SimpleCachableMarshalledValue((Serializable) attrs));
+         oos.close();
+         return bos.toByteArray();
+      }
+      finally
+      {
+         if (oos != null)
+         {
+            oos.close();
+         }
+         if (bos != null)
+         {
+            bos.close();
+         }
+      }
+   }
+
+   @SuppressWarnings("unchecked")
+   private static <T> T uncheckedCast(Object obj)
+   {
+      return (T) obj;
+   }
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/RDBMSStoreBase.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/TimestampBasedOutdatedSessionChecker.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/TimestampBasedOutdatedSessionChecker.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/TimestampBasedOutdatedSessionChecker.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,43 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import org.jboss.web.tomcat.service.session.ClusteredSession;
+import org.jboss.web.tomcat.service.session.OutdatedSessionChecker;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class TimestampBasedOutdatedSessionChecker
+      implements  OutdatedSessionChecker
+{
+   private final ExtendedDistributedCacheManager<? extends OutgoingDistributableSessionData> manager;
+   
+   public TimestampBasedOutdatedSessionChecker(ExtendedDistributedCacheManager<? extends OutgoingDistributableSessionData> manager)
+   {
+      if (manager == null)
+      {
+         throw new IllegalArgumentException("Null manager");
+      }
+      this.manager = manager;
+   }
+   
+   public boolean isSessionOutdated(ClusteredSession<? extends OutgoingDistributableSessionData> session)
+   {
+      boolean result = true;
+      String realId = session.getRealId();
+      Long timestamp = manager.getSessionTimestamp(realId);
+      if (timestamp != null)
+      {
+         result = session.getLastAccessedTimeInternal() < timestamp.longValue();
+      }
+      return result;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/TimestampBasedOutdatedSessionChecker.java
___________________________________________________________________
Name: svn:keywords
   + 

Added: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/VersionBasedOutdatedSessionChecker.java
===================================================================
--- branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/VersionBasedOutdatedSessionChecker.java	                        (rev 0)
+++ branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/VersionBasedOutdatedSessionChecker.java	2009-07-13 21:46:54 UTC (rev 91181)
@@ -0,0 +1,44 @@
+/**
+ * 
+ */
+package org.jboss.web.tomcat.service.session.persistent;
+
+import org.jboss.web.tomcat.service.session.ClusteredSession;
+import org.jboss.web.tomcat.service.session.OutdatedSessionChecker;
+import org.jboss.web.tomcat.service.session.distributedcache.spi.OutgoingDistributableSessionData;
+
+/**
+ *
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class VersionBasedOutdatedSessionChecker
+      implements  OutdatedSessionChecker
+{
+   private final ExtendedDistributedCacheManager<? extends OutgoingDistributableSessionData> manager;
+   
+   public VersionBasedOutdatedSessionChecker(ExtendedDistributedCacheManager<? extends OutgoingDistributableSessionData> manager)
+   {
+      if (manager == null)
+      {
+         throw new IllegalArgumentException("Null manager");
+      }
+      this.manager = manager;
+   }
+   
+   public boolean isSessionOutdated(ClusteredSession<? extends OutgoingDistributableSessionData> session)
+   {
+      boolean result = true;
+      String realId = session.getRealId();
+      Integer version = manager.getSessionVersion(realId);
+      if (version != null)
+      {
+         session.setVersionFromDistributedCache(version.intValue());
+         result = session.isOutdated();
+      }
+      return result;
+   }
+
+}


Property changes on: branches/JBPAPP_5_0/tomcat/src/main/org/jboss/web/tomcat/service/session/persistent/VersionBasedOutdatedSessionChecker.java
___________________________________________________________________
Name: svn:keywords
   + 

Modified: branches/JBPAPP_5_0/tools/etc/buildmagic/modules.ent
===================================================================
--- branches/JBPAPP_5_0/tools/etc/buildmagic/modules.ent	2009-07-13 21:17:25 UTC (rev 91180)
+++ branches/JBPAPP_5_0/tools/etc/buildmagic/modules.ent	2009-07-13 21:46:54 UTC (rev 91181)
@@ -28,6 +28,7 @@
   <pathelement path="${jboss.tomcat.lib}/jbossweb-cluster.aop"/>
   <pathelement path="${jboss.tomcat.root}/resource"/>
   <pathelement path="${jboss.tomcat.root}/deploy/jbossweb.sar/jboss-web-service.jar"/>
+  <pathelement path="${jboss.tomcat.root}/deploy/jboss-web.deployer/jboss-web-deployer.jar"/>
 </path>
 
 <!-- Cluster -->




More information about the jboss-cvs-commits mailing list