[jboss-cvs] JBossAS SVN: r79611 - in trunk: testsuite/src/main/org/jboss/test/cluster/web and 5 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Oct 16 19:12:00 EDT 2008
Author: bstansberry at jboss.com
Date: 2008-10-16 19:12:00 -0400 (Thu, 16 Oct 2008)
New Revision: 79611
Added:
trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/ClusteredSessionNotificationPolicyTestCase.java
trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/InvalidateSessionRequestHandler.java
trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/RemoveAttributesRequestHandler.java
trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/
trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockClusteredSessionNotificationPolicy.java
trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionAttributeListener.java
trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionListener.java
trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/SessionSpecListenerAttribute.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionManagementStatus.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCapability.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCause.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicy.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicyBase.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/IgnoreUndeployLegacyClusteredSessionNotificationPolicy.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/LegacyClusteredSessionNotificationPolicy.java
Modified:
trunk/testsuite/src/main/org/jboss/test/cluster/web/jvmroute/MockSession.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
Log:
[JBAS-5778] Improve servlet spec notification handling in clustered environment
Added: trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/ClusteredSessionNotificationPolicyTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/ClusteredSessionNotificationPolicyTestCase.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/defaultcfg/simpleweb/test/ClusteredSessionNotificationPolicyTestCase.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,704 @@
+/*
+ * 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.File;
+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.cache.pojo.PojoCache;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
+import org.jboss.metadata.web.jboss.ReplicationGranularity;
+import org.jboss.metadata.web.jboss.ReplicationTrigger;
+import org.jboss.test.JBossTestCase;
+import org.jboss.test.cluster.testutil.CacheConfigTestSetup;
+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.web.tomcat.service.session.JBossCacheManager;
+
+/**
+ * Tests of handling of servlet spec notifications.
+ *
+ * @author Brian Stansberry
+ */
+public class ClusteredSessionNotificationPolicyTestCase extends JBossTestCase
+{
+ protected static PojoCache[] pojoCaches = new PojoCache[2];
+
+ protected static long testId = System.currentTimeMillis();
+
+ protected static boolean useBuddyRepl = Boolean.valueOf(System.getProperty("jbosstest.cluster.web.cache.br")).booleanValue();
+
+ protected Logger log = Logger.getLogger(getClass());
+
+ protected Set<JBossCacheManager> managers = new HashSet<JBossCacheManager>();
+
+ protected Map<String, Object> allAttributes;
+ protected Map<String, Object> immutables;
+ protected Map<String, Object> mutables;
+ protected Map<String, Object> attributes;
+ protected SessionSpecListenerAttribute attribute = new SessionSpecListenerAttribute();
+ protected Map<String, Object> newAttributes;
+ protected SessionSpecListenerAttribute newAttribute = new SessionSpecListenerAttribute();
+
+ protected String origNotificationPolicy;
+
+ public ClusteredSessionNotificationPolicyTestCase(String name)
+ {
+ super(name);
+ }
+
+ public static Test suite() throws Exception
+ {
+ File tmpDir = new File(System.getProperty("java.io.tmpdir"));
+ File root = new File(tmpDir, ClusteredSessionNotificationPolicyTestCase.class.getSimpleName());
+ return CacheConfigTestSetup.getTestSetup(ClusteredSessionNotificationPolicyTestCase.class, pojoCaches, false, root.getAbsolutePath(), !useBuddyRepl, false);
+ }
+
+
+ @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 (JBossCacheManager manager : managers)
+ {
+ try
+ {
+ manager.stop();
+ }
+ catch (RuntimeException ignored)
+ {
+ log.debug("tearDown(): Caught exception cleaning up manager -- " + ignored.getLocalizedMessage());
+ }
+ }
+ managers.clear();
+
+ attribute.invocations.clear();
+ newAttribute.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
+ JBossCacheManager[] mgrs = getCacheManagers(warname, 1800, 1);
+ JBossCacheManager jbcm0 = mgrs[0];
+ JBossCacheManager jbcm1 = mgrs[1];
+
+ assertTrue(jbcm0.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+ MockClusteredSessionNotificationPolicy mcsnp0 = (MockClusteredSessionNotificationPolicy) jbcm0.getNotificationPolicy();
+ assertNotNull("capability set", mcsnp0.getClusteredSessionNotificationCapability());
+ mcsnp0.setResponse(notify);
+
+ assertTrue(jbcm1.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+ MockClusteredSessionNotificationPolicy mcsnp1 = (MockClusteredSessionNotificationPolicy) jbcm1.getNotificationPolicy();
+ assertNotNull("capability set", mcsnp1.getClusteredSessionNotificationCapability());
+ mcsnp1.setResponse(notify);
+
+ MockHttpSessionListener hsl0 = new MockHttpSessionListener();
+ MockHttpSessionAttributeListener hsal0 = new MockHttpSessionAttributeListener();
+ Context ctx = (Context) jbcm0.getContainer();
+ ctx.setApplicationLifecycleListeners(new Object[]{ hsl0 });
+ ctx.setApplicationEventListeners(new Object[]{ hsal0 });
+
+ MockHttpSessionListener hsl1 = new MockHttpSessionListener();
+ MockHttpSessionAttributeListener hsal1 = new MockHttpSessionAttributeListener();
+ ctx = (Context) jbcm1.getContainer();
+ ctx.setApplicationLifecycleListeners(new Object[]{ hsl1 });
+ ctx.setApplicationEventListeners(new Object[]{ hsal1 });
+
+ // Initial request
+ SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attributes, false);
+ SessionTestUtil.invokeRequest(jbcm0, 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(jbcm0, 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);
+
+ jbcm0.backgroundProcess();
+ jbcm1.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(jbcm0, 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(jbcm1, 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);
+
+ jbcm0.backgroundProcess();
+ jbcm1.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(jbcm0, 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
+ JBossCacheManager[] mgrs = getCacheManagers(warname, 2, 1);
+ JBossCacheManager jbcm0 = mgrs[0];
+ JBossCacheManager jbcm1 = mgrs[1];
+
+ assertTrue(jbcm0.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+ MockClusteredSessionNotificationPolicy mcsnp0 = (MockClusteredSessionNotificationPolicy) jbcm0.getNotificationPolicy();
+ assertNotNull("capability set", mcsnp0.getClusteredSessionNotificationCapability());
+ mcsnp0.setResponse(notify);
+
+ assertTrue(jbcm1.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+ MockClusteredSessionNotificationPolicy mcsnp1 = (MockClusteredSessionNotificationPolicy) jbcm1.getNotificationPolicy();
+ assertNotNull("capability set", mcsnp1.getClusteredSessionNotificationCapability());
+ mcsnp1.setResponse(notify);
+
+ MockHttpSessionListener hsl0 = new MockHttpSessionListener();
+ MockHttpSessionAttributeListener hsal0 = new MockHttpSessionAttributeListener();
+ Context ctx = (Context) jbcm0.getContainer();
+ ctx.setApplicationLifecycleListeners(new Object[]{ hsl0 });
+ ctx.setApplicationEventListeners(new Object[]{ hsal0 });
+
+ MockHttpSessionListener hsl1 = new MockHttpSessionListener();
+ MockHttpSessionAttributeListener hsal1 = new MockHttpSessionAttributeListener();
+ ctx = (Context) jbcm1.getContainer();
+ ctx.setApplicationLifecycleListeners(new Object[]{ hsl1 });
+ ctx.setApplicationEventListeners(new Object[]{ hsal1 });
+
+ // Initial request
+ SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attributes, false);
+ SessionTestUtil.invokeRequest(jbcm0, 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(jbcm1, 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);
+
+ jbcm0.backgroundProcess();
+ jbcm1.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);
+
+ jbcm0.backgroundProcess();
+ jbcm1.backgroundProcess();
+
+ if (!notify)
+ {
+ validateNoNotifications(hsl0, hsal0, hsl1, hsal1);
+ }
+ else
+ {
+ assertEquals(1, hsl0.invocations.size());
+ assertEquals(MockHttpSessionListener.Type.DESTROYED, hsl0.invocations.get(0));
+ 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(1, hsal1.invocations.size());
+ assertEquals(MockHttpSessionAttributeListener.Type.REMOVED, hsal1.invocations.get(0));
+ assertEquals(4, 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
+ JBossCacheManager[] mgrs = getCacheManagers(warname, 1800, -1);
+ JBossCacheManager jbcm0 = mgrs[0];
+ JBossCacheManager jbcm1 = mgrs[1];
+
+ assertTrue(jbcm0.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+ MockClusteredSessionNotificationPolicy mcsnp0 = (MockClusteredSessionNotificationPolicy) jbcm0.getNotificationPolicy();
+ assertNotNull("capability set", mcsnp0.getClusteredSessionNotificationCapability());
+ mcsnp0.setResponse(notify);
+
+ assertTrue(jbcm1.getNotificationPolicy() instanceof MockClusteredSessionNotificationPolicy);
+ MockClusteredSessionNotificationPolicy mcsnp1 = (MockClusteredSessionNotificationPolicy) jbcm1.getNotificationPolicy();
+ assertNotNull("capability set", mcsnp1.getClusteredSessionNotificationCapability());
+ mcsnp1.setResponse(notify);
+
+ MockHttpSessionListener hsl0 = new MockHttpSessionListener();
+ MockHttpSessionAttributeListener hsal0 = new MockHttpSessionAttributeListener();
+ Context ctx = (Context) jbcm0.getContainer();
+ ctx.setApplicationLifecycleListeners(new Object[]{ hsl0 });
+ ctx.setApplicationEventListeners(new Object[]{ hsal0 });
+
+ MockHttpSessionListener hsl1 = new MockHttpSessionListener();
+ MockHttpSessionAttributeListener hsal1 = new MockHttpSessionAttributeListener();
+ ctx = (Context) jbcm1.getContainer();
+ ctx.setApplicationLifecycleListeners(new Object[]{ hsl1 });
+ ctx.setApplicationEventListeners(new Object[]{ hsal1 });
+
+ // Initial request
+ SetAttributesRequestHandler setHandler = new SetAttributesRequestHandler(attributes, false);
+ SessionTestUtil.invokeRequest(jbcm0, 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);
+
+ }
+
+ jbcm0.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);
+
+
+ }
+
+ jbcm1.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 JBossCacheManager[] getCacheManagers(String warname, int maxInactive, int maxIdle)
+ throws Exception
+ {
+ JBossCacheManager jbcm0 = SessionTestUtil.createManager(warname, maxInactive, pojoCaches[0], null);
+ JBossWebMetaData metadata = SessionTestUtil.createWebMetaData(getReplicationGranularity(), getReplicationTrigger(), -1, maxIdle > 0, maxIdle, -1 ,false, 0);
+ // FIXME replacing setting system property w/ this:
+// metadata.setSessionNotificationPolicy(MockClusteredSessionNotificationPolicy.class.getName());
+ jbcm0.init(warname, metadata);
+ this.managers.add(jbcm0);
+ jbcm0.start();
+
+ JBossCacheManager jbcm1 = SessionTestUtil.createManager(warname, maxInactive, pojoCaches[1], null);
+ metadata = SessionTestUtil.createWebMetaData(getReplicationGranularity(), getReplicationTrigger(), -1, true, maxIdle, -1 ,false, 0);
+ // FIXME replacing setting system property w/ this:
+// metadata.setSessionNotificationPolicy(MockClusteredSessionNotificationPolicy.class.getName());
+ jbcm1.init(warname, metadata);
+ this.managers.add(jbcm1);
+ jbcm1.start();
+
+ return new JBossCacheManager[]{jbcm0, jbcm1};
+ }
+
+ protected void validateExpectedAttributes(Map<String, Object> expected, BasicRequestHandler handler)
+ {
+ assertFalse(handler.isNewSession());
+
+ if (handler.isCheckAttributeNames())
+ {
+ assertEquals(expected.size(), handler.getAttributeNames().size());
+ }
+ Map<String, Object> checked = handler.getCheckedAttributes();
+ assertEquals(expected.size(), checked.size());
+ for (Map.Entry<String, Object> entry : checked.entrySet())
+ assertEquals(entry.getKey(), expected.get(entry.getKey()), entry.getValue());
+
+ }
+
+ protected void validateNewSession(BasicRequestHandler handler)
+ {
+ assertTrue(handler.isNewSession());
+ assertEquals(handler.getCreationTime(), handler.getLastAccessedTime());
+ if (handler.isCheckAttributeNames())
+ {
+ assertEquals(0, handler.getAttributeNames().size());
+ }
+ Map<String, Object> checked = handler.getCheckedAttributes();
+ for (Map.Entry<String, Object> entry : checked.entrySet())
+ assertNull(entry.getKey(), entry.getValue());
+ }
+
+
+}
Modified: trunk/testsuite/src/main/org/jboss/test/cluster/web/jvmroute/MockSession.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/jvmroute/MockSession.java 2008-10-16 23:10:56 UTC (rev 79610)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/jvmroute/MockSession.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -30,6 +30,7 @@
import org.jboss.metadata.web.jboss.ReplicationTrigger;
import org.jboss.web.tomcat.service.session.AbstractJBossManager;
import org.jboss.web.tomcat.service.session.ClusteredSession;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
/**
* @author Brian Stansberry
@@ -84,7 +85,7 @@
}
@Override
- public void initAfterLoad(AbstractJBossManager manager)
+ public void initAfterLoad(AbstractJBossManager manager, ClusteredSessionNotificationCause cause)
{
}
Added: trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/InvalidateSessionRequestHandler.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/InvalidateSessionRequestHandler.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/InvalidateSessionRequestHandler.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,55 @@
+/*
+ * 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.mocks;
+
+import java.util.Set;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public class InvalidateSessionRequestHandler extends BasicRequestHandler
+{
+ /**
+ * Create a new RemoveAttributesRequestHandler.
+ *
+ */
+ public InvalidateSessionRequestHandler(Set<String> toCheck, boolean checkNames)
+ {
+ super(toCheck, checkNames);
+ }
+
+ public void handleRequest(Request request, Response response)
+ {
+ super.handleRequest(request, response);
+
+ getSession().invalidate();
+ }
+
+
+
+
+}
Added: trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/RemoveAttributesRequestHandler.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/RemoveAttributesRequestHandler.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/mocks/RemoveAttributesRequestHandler.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.test.cluster.web.mocks;
+
+import java.util.Set;
+
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public class RemoveAttributesRequestHandler extends BasicRequestHandler
+{
+ private Set<String> toRemove;
+
+ /**
+ * Create a new RemoveAttributesRequestHandler.
+ *
+ */
+ public RemoveAttributesRequestHandler(Set<String> toRemove, boolean checkNames)
+ {
+ super(toRemove, checkNames);
+ this.toRemove = toRemove;
+ }
+
+ public void handleRequest(Request request, Response response)
+ {
+ super.handleRequest(request, response);
+
+ HttpSession session = getSession();
+ for (String key : toRemove)
+ {
+ session.removeAttribute(key);
+ }
+ }
+
+
+
+
+}
Added: trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockClusteredSessionNotificationPolicy.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockClusteredSessionNotificationPolicy.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockClusteredSessionNotificationPolicy.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,124 @@
+/*
+ * 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.web.notification;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionManagementStatus;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicyBase;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public class MockClusteredSessionNotificationPolicy extends ClusteredSessionNotificationPolicyBase
+ implements
+ ClusteredSessionNotificationPolicy
+{
+ private boolean response;
+ public final List<PolicyInvocation> invocations = new ArrayList<PolicyInvocation>();
+
+ public enum Type { ACTIVATION, ATTRIBUTE, BINDING, SESSION };
+
+ /* (non-Javadoc)
+ * @see org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy#isHttpSessionAttributeListenerInvocationAllowed(org.jboss.web.tomcat.service.session.notification.ClusteredSessionManagementStatus, org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause, java.lang.String, boolean)
+ */
+ public boolean isHttpSessionAttributeListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName, boolean local)
+ {
+ invocations.add(new PolicyInvocation(Type.ATTRIBUTE, status, cause, attributeName, local));
+ return response;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy#isHttpSessionBindingListenerInvocationAllowed(org.jboss.web.tomcat.service.session.notification.ClusteredSessionManagementStatus, org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause, java.lang.String, boolean)
+ */
+ public boolean isHttpSessionBindingListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName, boolean local)
+ {
+ invocations.add(new PolicyInvocation(Type.BINDING, status, cause, attributeName, local));
+ return response;
+ }
+
+ /* (non-Javadoc)
+ * @see org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy#isHttpSessionListenerInvocationAllowed(org.jboss.web.tomcat.service.session.notification.ClusteredSessionManagementStatus, org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause, boolean)
+ */
+ public boolean isHttpSessionListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, boolean local)
+ {
+ invocations.add(new PolicyInvocation(Type.SESSION, status, cause, null, local));
+ return response;
+ }
+
+
+
+ public boolean isHttpSessionActivationListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName)
+ {
+ invocations.add(new PolicyInvocation(Type.ACTIVATION, status, cause, attributeName, true));
+ return response;
+ }
+
+ public boolean getResponse()
+ {
+ return response;
+ }
+
+ public void setResponse(boolean response)
+ {
+ this.response = response;
+ }
+
+ public List<PolicyInvocation> getInvocations()
+ {
+ return invocations;
+ }
+
+ public void clear()
+ {
+ invocations.clear();
+ }
+
+ public static class PolicyInvocation
+ {
+ public final Type type;
+ public final ClusteredSessionManagementStatus status;
+ public final ClusteredSessionNotificationCause cause;
+ public final String attributeName;
+ public final boolean local;
+
+ private PolicyInvocation(Type type, ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName, boolean local)
+ {
+ this.type = type;
+ this.status = status;
+ this.cause = cause;
+ this.attributeName = attributeName;
+ this.local = local;
+ }
+ }
+
+}
Added: trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionAttributeListener.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionAttributeListener.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionAttributeListener.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,67 @@
+/*
+ * 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.web.notification;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+
+import org.jboss.test.cluster.web.notification.SessionSpecListenerAttribute.Type;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public class MockHttpSessionAttributeListener implements HttpSessionAttributeListener
+{
+ public enum Type { ADDED, REMOVED, REPLACED };
+
+ public final List<Type> invocations = new ArrayList<Type>();
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent)
+ */
+ public void attributeAdded(HttpSessionBindingEvent arg0)
+ {
+ invocations.add(Type.ADDED);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionAttributeListener#attributeRemoved(javax.servlet.http.HttpSessionBindingEvent)
+ */
+ public void attributeRemoved(HttpSessionBindingEvent arg0)
+ {
+ invocations.add(Type.REMOVED);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)
+ */
+ public void attributeReplaced(HttpSessionBindingEvent arg0)
+ {
+ invocations.add(Type.REPLACED);
+ }
+
+}
Added: trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionListener.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionListener.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/MockHttpSessionListener.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,57 @@
+/*
+ * 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.web.notification;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public class MockHttpSessionListener implements HttpSessionListener
+{
+ public enum Type { CREATED, DESTROYED };
+
+ public final List<Type> invocations = new ArrayList<Type>();
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
+ */
+ public void sessionCreated(HttpSessionEvent arg0)
+ {
+ invocations.add(Type.CREATED);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
+ */
+ public void sessionDestroyed(HttpSessionEvent arg0)
+ {
+ invocations.add(Type.DESTROYED);
+ }
+
+}
Added: trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/SessionSpecListenerAttribute.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/SessionSpecListenerAttribute.java (rev 0)
+++ trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/SessionSpecListenerAttribute.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,80 @@
+/*
+ * 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.web.notification;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpSessionActivationListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionEvent;
+
+/**
+ * @author Brian Stansberry
+ *
+ */
+public class SessionSpecListenerAttribute implements HttpSessionBindingListener, HttpSessionActivationListener, Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ public enum Type { BOUND, UNBOUND, ACTIVATING, PASSIVATED };
+
+ public static final List<Type> invocations = new ArrayList<Type>();
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
+ */
+ public void valueBound(HttpSessionBindingEvent arg0)
+ {
+ getInvocations().add(Type.BOUND);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(javax.servlet.http.HttpSessionBindingEvent)
+ */
+ public void valueUnbound(HttpSessionBindingEvent arg0)
+ {
+ getInvocations().add(Type.UNBOUND);
+ }
+
+ public void sessionDidActivate(HttpSessionEvent arg0)
+ {
+ invocations.add(Type.ACTIVATING);
+ }
+
+ public void sessionWillPassivate(HttpSessionEvent arg0)
+ {
+ invocations.add(Type.PASSIVATED);
+ }
+
+ private List<Type> getInvocations()
+ {
+// if (invocations == null)
+// {
+// invocations = new ArrayList<Type>();
+// }
+ return invocations;
+ }
+}
Property changes on: trunk/testsuite/src/main/org/jboss/test/cluster/web/notification/SessionSpecListenerAttribute.java
___________________________________________________________________
Name: svn:mergeinfo
+
Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java 2008-10-16 23:10:56 UTC (rev 79610)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/ClusteredSession.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -49,6 +49,11 @@
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionMetadata;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSessionTimestamp;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionManagementStatus;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy;
+import org.jboss.web.tomcat.service.session.notification.LegacyClusteredSessionNotificationPolicy;
+
/**
* Abstract base class for session clustering based on StandardSession. Different session
* replication strategy can be implemented such as session- or attribute-based ones.
@@ -173,6 +178,16 @@
* Has this session only been accessed once?
*/
protected transient boolean firstAccess;
+
+ /**
+ * Policy that drives whether we issue servlet spec notifications.
+ */
+ protected transient ClusteredSessionNotificationPolicy notificationPolicy;
+
+ protected transient ClusteredSessionManagementStatus clusterStatus;
+
+ /** True if a call to activate() is needed to offset a preceding passivate() call */
+ protected transient boolean needsPostReplicateActivation;
/**
* The string manager for this package.
@@ -186,6 +201,7 @@
invalidationPolicy = replicationTrigger;
this.useJK = useJK;
this.firstAccess = true;
+ this.notificationPolicy = new LegacyClusteredSessionNotificationPolicy();
checkAlwaysReplicateTimestamp();
}
@@ -398,8 +414,9 @@
* This is called after loading a session to initialize the transient values.
*
* @param manager
+ * @param cause the cause of the load
*/
- public abstract void initAfterLoad(AbstractJBossManager manager);
+ public abstract void initAfterLoad(AbstractJBossManager manager, ClusteredSessionNotificationCause cause);
/**
* Propogate session to the internal store.
@@ -493,11 +510,15 @@
throw new IllegalArgumentException
(sm.getString("clusteredSession.setAttribute.iae"));
}
+
+ ClusteredSessionNotificationPolicy policy = getNotificationPolicy();
+
// Construct an event with the new value
HttpSessionBindingEvent event = null;
// Call the valueBound() method if necessary
- if (value instanceof HttpSessionBindingListener)
+ if (value instanceof HttpSessionBindingListener
+ && policy.isHttpSessionBindingListenerInvocationAllowed(this.clusterStatus, ClusteredSessionNotificationCause.MODIFY, name, true))
{
event = new HttpSessionBindingEvent(getSession(), name, value);
try
@@ -515,7 +536,8 @@
// Call the valueUnbound() method if necessary
if ((unbound != null) && (unbound != value) &&
- (unbound instanceof HttpSessionBindingListener))
+ (unbound instanceof HttpSessionBindingListener) &&
+ policy.isHttpSessionBindingListenerInvocationAllowed(this.clusterStatus, ClusteredSessionNotificationCause.MODIFY, name, true))
{
try
{
@@ -529,71 +551,74 @@
}
// Notify interested application event listeners
- Context context = (Context) manager.getContainer();
- Object listeners[] = context.getApplicationEventListeners();
- if (listeners == null)
- return;
- for (int i = 0; i < listeners.length; i++)
- {
- if (!(listeners[i] instanceof HttpSessionAttributeListener))
- continue;
- HttpSessionAttributeListener listener =
- (HttpSessionAttributeListener) listeners[i];
- try
+ if (policy.isHttpSessionAttributeListenerInvocationAllowed(this.clusterStatus, ClusteredSessionNotificationCause.MODIFY, name, true))
+ {
+ Context context = (Context) manager.getContainer();
+ Object lifecycleListeners[] = context.getApplicationEventListeners();
+ if (lifecycleListeners == null)
+ return;
+ for (int i = 0; i < lifecycleListeners.length; i++)
{
- if (unbound != null)
- {
- fireContainerEvent(context,
- "beforeSessionAttributeReplaced",
- listener);
- if (event == null)
- {
- event = new HttpSessionBindingEvent
- (getSession(), name, unbound);
- }
- listener.attributeReplaced(event);
- fireContainerEvent(context,
- "afterSessionAttributeReplaced",
- listener);
- }
- else
- {
- fireContainerEvent(context,
- "beforeSessionAttributeAdded",
- listener);
- if (event == null)
- {
- event = new HttpSessionBindingEvent
- (getSession(), name, value);
- }
- listener.attributeAdded(event);
- fireContainerEvent(context,
- "afterSessionAttributeAdded",
- listener);
- }
- }
- catch (Throwable t)
- {
+ if (!(lifecycleListeners[i] instanceof HttpSessionAttributeListener))
+ continue;
+ HttpSessionAttributeListener listener =
+ (HttpSessionAttributeListener) lifecycleListeners[i];
try
{
if (unbound != null)
{
fireContainerEvent(context,
+ "beforeSessionAttributeReplaced",
+ listener);
+ if (event == null)
+ {
+ event = new HttpSessionBindingEvent
+ (getSession(), name, unbound);
+ }
+ listener.attributeReplaced(event);
+ fireContainerEvent(context,
"afterSessionAttributeReplaced",
listener);
}
else
{
fireContainerEvent(context,
+ "beforeSessionAttributeAdded",
+ listener);
+ if (event == null)
+ {
+ event = new HttpSessionBindingEvent
+ (getSession(), name, value);
+ }
+ listener.attributeAdded(event);
+ fireContainerEvent(context,
"afterSessionAttributeAdded",
listener);
}
}
- catch (Exception e)
+ catch (Throwable t)
{
- ;
+ try
+ {
+ if (unbound != null)
+ {
+ fireContainerEvent(context,
+ "afterSessionAttributeReplaced",
+ listener);
+ }
+ else
+ {
+ fireContainerEvent(context,
+ "afterSessionAttributeAdded",
+ listener);
+ }
+ }
+ catch (Exception e)
+ {
+ ;
+ }
+ manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
}
- manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
}
}
}
@@ -630,7 +655,7 @@
boolean notify = true;
boolean localCall = true;
boolean localOnly = false;
- expire(notify, localCall, localOnly);
+ expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.INVALIDATE);
}
@@ -695,7 +720,7 @@
{
boolean localCall = true;
boolean localOnly = true;
- expire(notify, localCall, localOnly);
+ expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.TIMEOUT);
}
/**
@@ -720,8 +745,9 @@
* cluster nodes should be made aware of the expiration.
* Only meaningful if <code>localCall</code> is
* <code>true</code>.
+ * @param cause the cause of the expiration
*/
- public void expire(boolean notify, boolean localCall, boolean localOnly)
+ public void expire(boolean notify, boolean localCall, boolean localOnly, ClusteredSessionNotificationCause cause)
{
if (log.isTraceEnabled())
{
@@ -748,18 +774,20 @@
// Notify interested application event listeners
// FIXME - Assumes we call listeners in reverse order
Context context = (Context) manager.getContainer();
- Object listeners[] = context.getApplicationLifecycleListeners();
- if (notify && (listeners != null))
+ Object lifecycleListeners[] = context.getApplicationLifecycleListeners();
+ if (notify
+ && (lifecycleListeners != null)
+ && getNotificationPolicy().isHttpSessionListenerInvocationAllowed(this.clusterStatus, cause, localCall))
{
HttpSessionEvent event =
new HttpSessionEvent(getSession());
- for (int i = 0; i < listeners.length; i++)
+ for (int i = 0; i < lifecycleListeners.length; i++)
{
- int j = (listeners.length - 1) - i;
- if (!(listeners[j] instanceof HttpSessionListener))
+ int j = (lifecycleListeners.length - 1) - i;
+ if (!(lifecycleListeners[j] instanceof HttpSessionListener))
continue;
HttpSessionListener listener =
- (HttpSessionListener) listeners[j];
+ (HttpSessionListener) lifecycleListeners[j];
try
{
fireContainerEvent(context,
@@ -786,6 +814,7 @@
}
}
}
+
if (ACTIVITY_CHECK) {
accessCount.set(0);
}
@@ -799,7 +828,7 @@
// JBAS-1360 -- Unbind any objects associated with this session
String keys[] = keys();
for (int i = 0; i < keys.length; i++)
- removeAttributeInternal(keys[i], localCall, localOnly, notify);
+ removeAttributeInternal(keys[i], localCall, localOnly, notify, cause);
// Remove this session from our manager's active sessions
removeFromManager(localCall, localOnly);
@@ -832,7 +861,13 @@
}
}
+ @Override
public void passivate()
+ {
+ passivate(ClusteredSessionNotificationCause.PASSIVATION);
+ }
+
+ public void passivate(ClusteredSessionNotificationCause cause)
{
// Notify interested session event listeners
fireSessionEvent(Session.SESSION_PASSIVATED_EVENT, null);
@@ -841,6 +876,8 @@
{
boolean hasListener = false;
+ ClusteredSessionNotificationPolicy policy = getNotificationPolicy();
+
// Notify ActivationListeners
HttpSessionEvent event = null;
String keys[] = keys();
@@ -852,26 +889,40 @@
{
hasListener = true;
- if (event == null)
- event = new HttpSessionEvent(getSession());
- try
- {
- ((HttpSessionActivationListener)attribute).sessionWillPassivate(event);
+ if (policy.isHttpSessionActivationListenerInvocationAllowed(this.clusterStatus, cause, keys[i]))
+ {
+ if (event == null)
+ event = new HttpSessionEvent(getSession());
+
+ try
+ {
+ ((HttpSessionActivationListener)attribute).sessionWillPassivate(event);
+ }
+ catch (Throwable t)
+ {
+ manager.getContainer().getLogger().error
+ (sm.getString("clusteredSession.attributeEvent"), t);
+ }
}
- catch (Throwable t)
- {
- manager.getContainer().getLogger().error
- (sm.getString("clusteredSession.attributeEvent"), t);
- }
}
}
hasActivationListener = hasListener ? Boolean.TRUE : Boolean.FALSE;
}
+
+ if (cause != ClusteredSessionNotificationCause.PASSIVATION)
+ {
+ this.needsPostReplicateActivation = true;
+ }
}
public void activate()
{
+ activate(ClusteredSessionNotificationCause.ACTIVATION);
+ }
+
+ public void activate(ClusteredSessionNotificationCause cause)
+ {
// Notify interested session event listeners
fireSessionEvent(Session.SESSION_ACTIVATED_EVENT, null);
@@ -881,6 +932,8 @@
boolean hasListener = false;
+ ClusteredSessionNotificationPolicy policy = getNotificationPolicy();
+
HttpSessionEvent event = null;
String keys[] = keys();
Map attrs = getAttributesInternal();
@@ -890,23 +943,37 @@
if (attribute instanceof HttpSessionActivationListener)
{
hasListener = true;
- if (event == null)
- event = new HttpSessionEvent(getSession());
- try
+
+ if (policy.isHttpSessionActivationListenerInvocationAllowed(this.clusterStatus, cause, keys[i]))
{
- ((HttpSessionActivationListener)attribute).sessionDidActivate(event);
+ if (event == null)
+ event = new HttpSessionEvent(getSession());
+ try
+ {
+ ((HttpSessionActivationListener)attribute).sessionDidActivate(event);
+ }
+ catch (Throwable t)
+ {
+ manager.getContainer().getLogger().error
+ (sm.getString("clusteredSession.attributeEvent"), t);
+ }
}
- catch (Throwable t)
- {
- manager.getContainer().getLogger().error
- (sm.getString("clusteredSession.attributeEvent"), t);
- }
}
}
hasActivationListener = hasListener ? Boolean.TRUE : Boolean.FALSE;
}
+
+ if (cause != ClusteredSessionNotificationCause.ACTIVATION)
+ {
+ this.needsPostReplicateActivation = false;
+ }
}
+
+ public boolean getNeedsPostReplicateActivation()
+ {
+ return needsPostReplicateActivation;
+ }
// TODO uncomment when work on JBAS-1900 is completed
// public void removeNote(String name)
@@ -972,6 +1039,8 @@
lastReplicated = 0;
maxUnreplicatedInterval = 0;
alwaysReplicateTimestamp = true;
+ this.notificationPolicy = null;
+ this.clusterStatus = null;
}
/**
@@ -995,8 +1064,23 @@
// Parse the real id first, as super.setId() calls add(),
// which depends on having the real id
parseRealId(id);
- super.setId(id);
+
+ // TODO -- should we bypass this if realId hasn't changed? We're removing
+ // and readding every time we fail over, when all we want is a
+ // jvmRoute change to the session id
+
+ if ((this.id != null) && (manager != null))
+ manager.remove(this);
+
+ this.id = id;
+
+ this.clusterStatus = new ClusteredSessionManagementStatus(this.realId, true, null, null);
+
+ if (manager != null)
+ manager.add(this);
}
+
+
/**
* Set the authenticated Principal that is associated with this Session.
@@ -1037,6 +1121,53 @@
sessionMetadataDirty();
}
+ @Override
+ public void tellNew()
+ {
+ tellNew(ClusteredSessionNotificationCause.CREATE);
+ }
+
+ public void tellNew(ClusteredSessionNotificationCause cause)
+ {
+ // Notify interested session event listeners
+ fireSessionEvent(Session.SESSION_CREATED_EVENT, null);
+
+ // Notify interested application event listeners
+ if (getNotificationPolicy().isHttpSessionListenerInvocationAllowed(this.clusterStatus, cause, true))
+ {
+ Context context = (Context) manager.getContainer();
+ Object lifecycleListeners[] = context.getApplicationLifecycleListeners();
+ if (lifecycleListeners != null)
+ {
+ HttpSessionEvent event = new HttpSessionEvent(getSession());
+ for (int i = 0; i < lifecycleListeners.length; i++)
+ {
+ if (!(lifecycleListeners[i] instanceof HttpSessionListener))
+ continue;
+ HttpSessionListener listener = (HttpSessionListener) lifecycleListeners[i];
+ try
+ {
+ fireContainerEvent(context, "beforeSessionCreated", listener);
+ listener.sessionCreated(event);
+ fireContainerEvent(context, "afterSessionCreated", listener);
+ }
+ catch (Throwable t)
+ {
+ try
+ {
+ fireContainerEvent(context, "afterSessionCreated", listener);
+ }
+ catch (Exception e)
+ {
+ ;
+ }
+ manager.getContainer().getLogger().error(sm.getString("standardSession.sessionEvent"), t);
+ }
+ }
+ }
+ }
+ }
+
public String toString()
{
StringBuffer buf = new StringBuffer();
@@ -1081,6 +1212,16 @@
return excluded;
}
+
+ protected ClusteredSessionNotificationPolicy getNotificationPolicy()
+ {
+ return notificationPolicy;
+ }
+
+ protected void setNotificationPolicy(ClusteredSessionNotificationPolicy notificationPolicy)
+ {
+ this.notificationPolicy = notificationPolicy;
+ }
public void update(Integer version, DistributableSessionTimestamp timestamp,
DistributableSessionMetadata metadata, Map attributes)
@@ -1120,6 +1261,10 @@
// a heavy cost.
this.lastReplicated = this.creationTime;
+ this.notificationPolicy = new LegacyClusteredSessionNotificationPolicy();
+
+ this.clusterStatus = new ClusteredSessionManagementStatus(this.realId, true, null, null);
+
checkAlwaysReplicateTimestamp();
// TODO uncomment when work on JBAS-1900 is completed
@@ -1170,7 +1315,7 @@
{
boolean localCall = true;
boolean localOnly = false;
- removeAttributeInternal(name, localCall, localOnly, notify);
+ removeAttributeInternal(name, localCall, localOnly, notify, ClusteredSessionNotificationCause.MODIFY);
}
/**
@@ -1186,11 +1331,13 @@
* @param localOnly <code>true</code> if the removal should not be
* replicated around the cluster
* @param notify <code>true</code> if listeners should be notified
+ * @param cause the cause of the removal
*/
protected void removeAttributeInternal(String name,
boolean localCall,
boolean localOnly,
- boolean notify)
+ boolean notify,
+ ClusteredSessionNotificationCause cause)
{
// Remove this attribute from our collection
Object value = removeJBossInternalAttribute(name, localCall, localOnly);
@@ -1201,53 +1348,59 @@
return;
}
+ ClusteredSessionNotificationPolicy policy = getNotificationPolicy();
+
// Call the valueUnbound() method if necessary
HttpSessionBindingEvent event = null;
- if (value instanceof HttpSessionBindingListener)
+ if (value instanceof HttpSessionBindingListener
+ && policy.isHttpSessionBindingListenerInvocationAllowed(this.clusterStatus, cause, name, localCall))
{
event = new HttpSessionBindingEvent(getSession(), name, value);
((HttpSessionBindingListener) value).valueUnbound(event);
}
// Notify interested application event listeners
- Context context = (Context) manager.getContainer();
- Object listeners[] = context.getApplicationEventListeners();
- if (listeners == null)
- return;
- for (int i = 0; i < listeners.length; i++)
+ if (policy.isHttpSessionAttributeListenerInvocationAllowed(this.clusterStatus, cause, name, localCall))
{
- if (!(listeners[i] instanceof HttpSessionAttributeListener))
- continue;
- HttpSessionAttributeListener listener =
- (HttpSessionAttributeListener) listeners[i];
- try
+ Context context = (Context) manager.getContainer();
+ Object lifecycleListeners[] = context.getApplicationEventListeners();
+ if (lifecycleListeners == null)
+ return;
+ for (int i = 0; i < lifecycleListeners.length; i++)
{
- fireContainerEvent(context,
- "beforeSessionAttributeRemoved",
- listener);
- if (event == null)
- {
- event = new HttpSessionBindingEvent
- (getSession(), name, value);
- }
- listener.attributeRemoved(event);
- fireContainerEvent(context,
- "afterSessionAttributeRemoved",
- listener);
- }
- catch (Throwable t)
- {
+ if (!(lifecycleListeners[i] instanceof HttpSessionAttributeListener))
+ continue;
+ HttpSessionAttributeListener listener =
+ (HttpSessionAttributeListener) lifecycleListeners[i];
try
{
fireContainerEvent(context,
+ "beforeSessionAttributeRemoved",
+ listener);
+ if (event == null)
+ {
+ event = new HttpSessionBindingEvent
+ (getSession(), name, value);
+ }
+ listener.attributeRemoved(event);
+ fireContainerEvent(context,
"afterSessionAttributeRemoved",
listener);
}
- catch (Exception e)
+ catch (Throwable t)
{
- ;
+ try
+ {
+ fireContainerEvent(context,
+ "afterSessionAttributeRemoved",
+ listener);
+ }
+ catch (Exception e)
+ {
+ ;
+ }
+ manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
}
- manager.getContainer().getLogger().error(sm.getString("standardSession.attributeEvent"), t);
}
}
Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java 2008-10-16 23:10:56 UTC (rev 79610)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheClusteredSession.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -24,6 +24,7 @@
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributableSession;
import org.jboss.web.tomcat.service.session.distributedcache.spi.DistributedCacheManager;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
/**
* Common superclass of ClusteredSession types that use JBossCache
@@ -52,6 +53,7 @@
super(manager, manager.getReplicationTrigger(), manager.getUseJK());
int maxUnrep = manager.getMaxUnreplicatedInterval() * 1000;
setMaxUnreplicatedInterval(maxUnrep);
+ establishNotificationPolicy();
establishProxy();
}
@@ -61,19 +63,26 @@
*
* @param manager the manager for this session
*/
- public void initAfterLoad(AbstractJBossManager manager)
+ @Override
+ public void initAfterLoad(AbstractJBossManager manager, ClusteredSessionNotificationCause cause)
{
- // Our manager and proxy may have been lost if we were recycled,
- // so reestablish them
+ // Our manager, notification policy and proxy may have been lost
+ // if we were replicated, so reestablish them
setManager(manager);
+ establishNotificationPolicy();
establishProxy();
// Since attribute map may be transient, we may need to populate it
// from the underlying store.
populateAttributes();
+ if (cause == ClusteredSessionNotificationCause.ACTIVATION)
+ {
+ this.needsPostReplicateActivation = true;
+ }
+
// Notify all attributes of type HttpSessionActivationListener (SRV 7.7.2)
- this.activate();
+ this.activate(cause);
// We are no longer outdated vis a vis distributed cache
clearOutdated();
@@ -178,5 +187,10 @@
{
return removeJBossInternalAttribute(name, localCall, localOnly);
}
+
+ protected void establishNotificationPolicy()
+ {
+ setNotificationPolicy(((JBossCacheManager)manager).getNotificationPolicy());
+ }
}
Modified: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java 2008-10-16 23:10:56 UTC (rev 79610)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/JBossCacheManager.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -56,6 +56,11 @@
import org.jboss.web.tomcat.service.session.distributedcache.spi.FieldBasedDistributedCacheManager;
import org.jboss.web.tomcat.service.session.distributedcache.spi.LocalDistributableSessionManager;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCapability;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationCause;
+import org.jboss.web.tomcat.service.session.notification.ClusteredSessionNotificationPolicy;
+import org.jboss.web.tomcat.service.session.notification.LegacyClusteredSessionNotificationPolicy;
+
/**
* Implementation of a clustered session manager for
* catalina using JBossCache replication.
@@ -133,6 +138,9 @@
private int maxUnreplicatedInterval_ = -1;
+ private String notificationPolicyClass_;
+ private ClusteredSessionNotificationPolicy notificationPolicy_;
+
// ---------------------------------------------------------- Constructors
public JBossCacheManager() throws ClusteringNotSupportedException
@@ -199,6 +207,9 @@
this.cacheConfigName_ = repCfg.getCacheName();
+ // FIXME -- JBAS-5778
+ //this.notificationPolicyClass_ = webMetaData.getSessionNotificationPolicy();
+
// Initing the proxy would be better in start, but we do it here so we
// can detect ClusteringNotSupportedException at this deploy stage
initCacheProxy();
@@ -277,7 +288,7 @@
// Notify all session attributes that they get serialized (SRV 7.7.2)
long begin = System.currentTimeMillis();
- session.passivate();
+ session.passivate(ClusteredSessionNotificationCause.REPLICATION);
long elapsed = System.currentTimeMillis() - begin;
stats_.updatePassivationStats(realId, elapsed);
@@ -442,6 +453,7 @@
}
session.setId(sessionId); // Setting the id leads to a call to add()
+ session.tellNew(ClusteredSessionNotificationCause.CREATE);
if (trace_)
{
@@ -492,12 +504,15 @@
log_.trace("Checking for session " + realId + " in the distributed cache");
session = loadSession(realId);
- if (session != null)
- {
- add(session);
- // TODO should we advise of a new session?
- //tellNew();
- }
+// if (session != null)
+// {
+// add(session);
+// // We now notify, since we've added a policy to allow listeners
+// // to discriminate. But the default policy will not allow the
+// // notification to be emitted for FAILOVER, so the standard
+// // behavior is unchanged.
+// session.tellNew(ClusteredSessionNotificationCause.FAILOVER);
+// }
}
else if (session != null && session.isOutdated())
{
@@ -512,6 +527,13 @@
{
// Add this session to the set of those potentially needing replication
SessionReplicationContext.bindSession(session, snapshotManager_);
+
+ // If we previously called passivate() on the session due to
+ // replication, we need to make an offsetting activate() call
+ if (session.getNeedsPostReplicateActivation())
+ {
+ session.activate(ClusteredSessionNotificationCause.REPLICATION);
+ }
}
return session;
@@ -920,7 +942,7 @@
try
{
Thread.currentThread().setContextClassLoader(tcl_);
- session.expire(notify, localCall, localOnly);
+ session.expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.INVALIDATE);
}
finally
{
@@ -1153,6 +1175,16 @@
return proxy_;
}
+ public ClusteredSessionNotificationPolicy getNotificationPolicy()
+ {
+ return notificationPolicy_;
+ }
+
+ public void setNotificationPolicy_(ClusteredSessionNotificationPolicy notificationPolicy_)
+ {
+ this.notificationPolicy_ = notificationPolicy_;
+ }
+
// --------------------------------------------------------------- Overrides
/**
@@ -1429,6 +1461,8 @@
long begin = System.currentTimeMillis();
boolean mustAdd = false;
+ boolean passivated = false;
+
JBossCacheClusteredSession session = (JBossCacheClusteredSession) sessions_.get(realId);
if (session == null)
@@ -1438,6 +1472,9 @@
// a replication message from another server
mustAdd = true;
session = createEmptyClusteredSession();
+
+ OwnedSessionUpdate osu = unloadedSessions_.get(realId);
+ passivated = (osu != null && osu.passivated);
}
synchronized (session)
@@ -1469,7 +1506,9 @@
if (session != null)
{
- session.initAfterLoad(this);
+ ClusteredSessionNotificationCause cause = passivated ? ClusteredSessionNotificationCause.ACTIVATION
+ : ClusteredSessionNotificationCause.FAILOVER;
+ session.initAfterLoad(this, cause);
}
}
catch (Exception ex)
@@ -1511,7 +1550,13 @@
if (session != null)
{
if (mustAdd)
+ {
add(session, false); // don't replicate
+ if (!passivated)
+ {
+ session.tellNew(ClusteredSessionNotificationCause.FAILOVER);
+ }
+ }
long elapsed = System.currentTimeMillis() - begin;
stats_.updateLoadStats(realId, elapsed);
@@ -1624,7 +1669,7 @@
// Tell the proxy to ignore cache notifications we are about
// to generate for this session.
SessionReplicationContext.startCacheActivity();
- session.passivate();
+ session.passivate(ClusteredSessionNotificationCause.PASSIVATION);
proxy_.evictSession(realId);
sessionPassivated();
}
@@ -1727,9 +1772,9 @@
log_.error(msg, e);
throw new LifecycleException(msg, e);
}
- }
+ }
- // Validate attributes
+ initClusteredSessionNotificationPolicy();
// Create the JBossCacheService
try
@@ -1796,6 +1841,32 @@
proxy_ = distributedCacheManagerFactory.getDistributedCacheManager(cacheConfigName_);
}
}
+
+ private void initClusteredSessionNotificationPolicy()
+ {
+ if (this.notificationPolicyClass_ == null || this.notificationPolicyClass_.length() == 0)
+ {
+ this.notificationPolicyClass_ = System.getProperty("jboss.web.clustered.session.notification.policy",
+ LegacyClusteredSessionNotificationPolicy.class.getName());
+ }
+
+ try
+ {
+ this.notificationPolicy_ = (ClusteredSessionNotificationPolicy) Thread.currentThread().getContextClassLoader().loadClass(this.notificationPolicyClass_).newInstance();
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to instantiate " +
+ ClusteredSessionNotificationPolicy.class.getName() +
+ " " + this.notificationPolicyClass_, e);
+ }
+
+ this.notificationPolicy_.setClusteredSessionNotificationCapability(new ClusteredSessionNotificationCapability());
+ }
/**
* Gets the ids of all sessions in the distributed cache and adds
@@ -2039,7 +2110,7 @@
boolean notify = true;
boolean localCall = true;
boolean localOnly = true;
- ses.expire(notify, localCall, localOnly);
+ ses.expire(notify, localCall, localOnly, ClusteredSessionNotificationCause.UNDEPLOY);
}
}
catch (Throwable t)
@@ -2098,6 +2169,8 @@
{
super.start();
+ initClusteredSessionNotificationPolicy();
+
// Start the JBossCacheService
// Will need to pass the classloader that is associated with this
// web app so de-serialization will work correctly.
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionManagementStatus.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionManagementStatus.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionManagementStatus.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,127 @@
+/*
+ * 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.notification;
+
+/**
+ * Encapsulates the status of how the local container is managing the
+ * given session.
+ *
+ * @author Brian Stansberry
+ */
+public class ClusteredSessionManagementStatus
+{
+ private final String realId;
+ private final boolean locallyUsed;
+ private final Boolean locallyActive;
+ private final Boolean locallyOwned;
+
+ /**
+ * Create a new ClusteredSessionManagementStatus.
+ *
+ * @param realId the id of the session, excluding any jvmRoute.
+ * @param locallyUsed whether the session has been provided to the
+ * application on this node.
+ * @param locallyActive whether this node is the most recent one to
+ * handle a request for the session; <code>null</code>
+ * if unknown
+ * @param locallyOwned whether this node is the "owner" of the session,
+ * <code>null</code> if unknown or the concept of
+ * ownership is unsupported.
+ */
+ public ClusteredSessionManagementStatus(String realId,
+ boolean locallyUsed,
+ Boolean locallyActive,
+ Boolean locallyOwned)
+ {
+ if (realId == null)
+ throw new IllegalArgumentException("realId is null");
+
+ this.realId = realId;
+ this.locallyUsed = locallyUsed;
+ // If we haven't been locallyUsed, we can't be locallyActive
+ this.locallyActive = (locallyUsed ? locallyActive : Boolean.FALSE);
+ // If we are locallyActive, we are locally owned
+ this.locallyOwned = (Boolean.TRUE.equals(locallyActive) ? Boolean.TRUE : locallyOwned);
+ }
+
+ /**
+ * Gets the id of the session, excluding any jvmRoute that may have
+ * been appended if JK is used.
+ *
+ * @return the id. Will not return <code>null</code>.
+ */
+ public String getRealId()
+ {
+ return realId;
+ }
+
+ /**
+ * Gets whether an HttpSession object for the given session has been
+ * returned from the container to the application on this node.
+ *
+ * @return <code>true</code> if the session has been used locally,
+ * <code>false</code> if not.
+ */
+ public boolean isLocallyUsed()
+ {
+ return locallyUsed;
+ }
+
+ /**
+ * Gets whether an HttpSession object for the given session has been
+ * returned from the container to the application on this node AND
+ * this node is the last one to handle a request for the session.
+ *
+ * @return <code>true</code> if the above conditions are true and the
+ * container is sure of this, <code>false</code> if they are not
+ * true and the container knows this, or <code>null</code> if the
+ * container is unsure if this node is the last one to handle a
+ * request for the session.
+ *
+ * @see ClusteredSessionNotificationCapability#isLocallyActiveAware()
+ */
+ public Boolean getLocallyActive()
+ {
+ return locallyActive;
+ }
+
+ /**
+ * Gets whether this node considers itself to be the "owner" of the session;
+ * i.e. the one primarily responsible for managing its lifecycle. Note that
+ * a node that is undeploying a war will always give up ownership of its
+ * sessions if it is aware of other nodes in the cluster that still have
+ * the war deployed.
+ *
+ * @return <code>true</code> if the container knows it is the owner,
+ * <code>false</code> if it knows it is not the owner, or
+ * <code>null</code> if the container is unsure about ownership
+ * or does not recognize the concept of ownership.
+ *
+ * @see ClusteredSessionNotificationCapability#isLocallyOwnedAware()
+ */
+ public Boolean getLocallyOwned()
+ {
+ return locallyOwned;
+ }
+
+}
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCapability.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCapability.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCapability.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,133 @@
+/*
+ * 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.notification;
+
+
+/**
+ * Encapsulates information about the container's capability to issue
+ * servlet spec notifications under different condititions. Implementations of
+ * {@link ClusteredSessionNotificationPolicy} can use this
+ * information to get a sense of the capabilities of the container.
+ *
+ * @author Brian Stansberry
+ */
+public class ClusteredSessionNotificationCapability
+{
+
+ /**
+ * Does the container support invoking <code>HttpSessionListener</code>
+ * callbacks under the given conditions?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param local <code>true</code> if the event driving the notification
+ * originated on this node; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if the notification is supported,
+ * <code>false</code> if not
+ */
+ public boolean isHttpSessionListenerInvocationSupported(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ boolean local)
+ {
+ return local && status.isLocallyUsed() && !ClusteredSessionNotificationCause.STATE_TRANSFER.equals(cause);
+ }
+
+ /**
+ * Under the given conditions, does the container support invoking
+ * <code>HttpSessionAttributeListener</code> callbacks?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param local <code>true</code> if the event driving the notification
+ * originated on this node; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if the notification is supported,
+ * <code>false</code> if not
+ */
+ public boolean isHttpSessionAttributeListenerInvocationSupported(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ boolean local)
+ {
+ return local && status.isLocallyUsed() && !ClusteredSessionNotificationCause.STATE_TRANSFER.equals(cause);
+ }
+
+ /**
+ * Under the given conditions, does the container support invoking
+ * <code>HttpSessionBindingListener</code> callbacks?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param local <code>true</code> if the event driving the notification
+ * originated on this node; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if the notification is supported,
+ * <code>false</code> if not
+ */
+ public boolean isHttpSessionBindingListenerInvocationSupported(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ boolean local)
+ {
+ return local && status.isLocallyUsed() && !ClusteredSessionNotificationCause.STATE_TRANSFER.equals(cause);
+ }
+
+ /**
+ * Is the container able to distinguish whether a session that has been
+ * {@link ClusteredSessionManagementStatus#isLocallyUsed() locally used}
+ * is also {@link ClusteredSessionManagementStatus#getLocallyActive() locally active}?
+ *
+ * @return <code>true</code> if the container is able to make this distinction;
+ * <code>false</code> if not
+ */
+ public boolean isLocallyActiveAware()
+ {
+ return false;
+ }
+
+ /**
+ * Is the container able to distinguish whether a session is
+ * {@link ClusteredSessionManagementStatus#getLocallyOwned() locally owned}?
+ *
+ * @return <code>true</code> if the container is able to make this distinction;
+ * <code>false</code> if not
+ */
+ public boolean isLocallyOwnedAware()
+ {
+ return false;
+ }
+
+ /**
+ * Returns whether the local container is aware of events on remote nodes
+ * that could give rise to notifications.
+ *
+ * @param cause the cause
+ * @return <code>true</code> if the local container is aware of the
+ * remote event, <code>false</code> if not.
+ */
+ public boolean isRemoteCauseAware(ClusteredSessionNotificationCause cause)
+ {
+ return ClusteredSessionNotificationCause.CREATE.equals(cause)
+ || ClusteredSessionNotificationCause.MODIFY.equals(cause)
+ || ClusteredSessionNotificationCause.INVALIDATE.equals(cause);
+ }
+}
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCause.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCause.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationCause.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,115 @@
+/*
+ * 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.notification;
+
+/**
+ * Reasons why a servlet spec notification for a clustered session is being
+ * generated.
+ *
+ * @author Brian Stansberry
+ */
+public enum ClusteredSessionNotificationCause
+{
+ /**
+ * Session has been newly created.
+ */
+ CREATE,
+
+ /**
+ * Session has been modified by the application.
+ */
+ MODIFY,
+
+ /**
+ * Session has failed over and is now in use on the local node.
+ */
+ FAILOVER,
+
+ /**
+ * Session has failed over and is no longer active on the local node.
+ */
+ FAILAWAY,
+
+ /**
+ * Session is being invalidated by the application.
+ */
+ INVALIDATE,
+
+ /**
+ * Session is being expired by the container due to timeout.
+ */
+ TIMEOUT,
+
+ /**
+ * Session is being expired by the container due to undeploy of the
+ * web application.
+ */
+ UNDEPLOY,
+
+ /**
+ * Local node became aware of a session active on another node as
+ * a result of the local node receiving a bulk state transfer due to
+ * its being elected to provide backup for that other node's sessions.
+ */
+ STATE_TRANSFER,
+
+ /**
+ * The session is being passivated.
+ */
+ PASSIVATION,
+
+ /**
+ * The session is being activated.
+ */
+ ACTIVATION,
+
+ /**
+ * The session is being replicated.
+ */
+ REPLICATION//,
+
+// /**
+// * Local node has taken "ownership" of a session for a reason other than
+// * failover; i.e. the session hasn't become active on the local node. In this
+// * case the local node would have become aware of the session earlier (i.e.
+// * via {@link #CREATE} or {@link #STATE_TRANSFER}) and these notifications
+// * would signal the local node taking greater responsibility for the session.
+// * Typically a policy implementation would not allow notifications for a
+// * remotely originated CREATE or for a STATE_TRANSFER if it allows
+// * notifications for TAKE_OWNERSHIP, and vice versa. Otherwise, multiple
+// * notifications would be received for the same session.
+// */
+// TAKE_OWNERSHIP,
+//
+// /**
+// * Local node has relinquised "ownership" of a session for a reason other than
+// * {@link #FAILAWAY} {@link #INVALIDATE}, {@link #TIMEOUT} or {@link #UNDEPLOY};
+// * i.e. some other node is taking over as the owner of session.
+// * Typically a policy implementation would not allow notifications for a
+// * remotely originated CREATE or for a STATE_TRANSFER if it allows
+// * notifications for TAKE_OWNERSHIP, and vice versa. Otherwise, multiple
+// * notifications would be received for the same session.
+// */
+// RELINQUISH_OWNERSHIP
+
+}
\ No newline at end of file
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicy.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicy.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicy.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,132 @@
+/*
+ * 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.notification;
+
+/**
+ * Policy for determining whether the servlet spec notifications related
+ * to session events are allowed to be emitted on the local cluster node.
+ * <p>
+ * <strong>Note:</strong> The use of the word <strong>allowed</strong> above
+ * is intentional; if a given policy implementation returns <code>true</code>
+ * from one of the methods in this interface, that does not mean the listener
+ * will be invoked by the container, nor does the presence of a method in this
+ * interface imply that it will be invoked by the container in all cases. The
+ * only contract this interface creates is that before invoking a listener
+ * method, the container will invoke an implementation of this policy to
+ * get permission and will not invoke the listeners if this policy returns
+ * <code>false</code>. If the container does not support emitting notifications
+ * in certain cases, it may not bother checking if the notification is allowed,
+ * and even if it checks, it still will not emit the notification.
+ * </p>
+ * <p>
+ * An example of a case where the container may not support emitting a
+ * notification is for a session that has never been used locally.
+ * </p>
+ *
+ * @author Brian Stansberry
+ */
+public interface ClusteredSessionNotificationPolicy
+{
+ /**
+ * Are invocations of <code>HttpSessionListener</code> callbacks
+ * allowed under the given conditions?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param local <code>true</code> if the event driving the notification
+ * originated on this node; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if the notification is allowed,
+ * <code>false</code> if not
+ */
+ boolean isHttpSessionListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ boolean local);
+
+
+ /**
+ * Under the given conditions, are invocations of
+ * <code>HttpSessionAttributeListener</code> callbacks allowed?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param attributeName value that would be passed to the <code>name</code>
+ * param of the <code>HttpSessionBindingEvent</code> if
+ * the listener were invoked
+ * @param local <code>true</code> if the event driving the notification
+ * originated on this node; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if the notification is allowed,
+ * <code>false</code> if not
+ */
+ boolean isHttpSessionAttributeListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ String attributeName,
+ boolean local);
+
+ /**
+ * Under the given conditions, are invocations of
+ * <code>HttpSessionBindingListener</code> callbacks allowed?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param attributeName value that would be passed to the <code>name</code>
+ * param of the <code>HttpSessionBindingEvent</code> if
+ * the listener were invoked
+ * @param local <code>true</code> if the event driving the notification
+ * originated on this node; <code>false</code> otherwise
+ *
+ * @return <code>true</code> if the notification is allowed,
+ * <code>false</code> if not
+ */
+ boolean isHttpSessionBindingListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ String attributeName,
+ boolean local);
+
+ /**
+ * Under the given conditions, are invocations of
+ * <code>HttpSessionActivationListener</code> callbacks allowed?
+ *
+ * @param status the status of the session
+ * @param cause the cause of the session notification
+ * @param attributeName value that would be passed to the <code>name</code>
+ * param of the <code>HttpSessionEvent</code> if
+ * the listener were invoked
+ *
+ * @return <code>true</code> if the notification is allowed,
+ * <code>false</code> if not
+ */
+ boolean isHttpSessionActivationListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause,
+ String attributeName);
+
+ /**
+ * Provides the policy information about the container's capabilities with
+ * respect to issuing notifications. Will be invoked by the container before
+ * the first invocation of any of the other methods in this interface.
+ *
+ * @param capability the capability, Will not be <code>null</code>.
+ */
+ void setClusteredSessionNotificationCapability(ClusteredSessionNotificationCapability capability);
+}
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicyBase.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicyBase.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/ClusteredSessionNotificationPolicyBase.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,29 @@
+package org.jboss.web.tomcat.service.session.notification;
+
+/**
+ * Base superclass for a {@link ClusteredSessionNotificationPolicy} implementation.
+ *
+ * @author Brian Stansberry
+ *
+ */
+public class ClusteredSessionNotificationPolicyBase
+{
+
+ private ClusteredSessionNotificationCapability capability;
+
+ public ClusteredSessionNotificationPolicyBase()
+ {
+ super();
+ }
+
+ public void setClusteredSessionNotificationCapability(ClusteredSessionNotificationCapability capability)
+ {
+ this.capability = capability;
+ }
+
+ public ClusteredSessionNotificationCapability getClusteredSessionNotificationCapability()
+ {
+ return this.capability;
+ }
+
+}
\ No newline at end of file
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/IgnoreUndeployLegacyClusteredSessionNotificationPolicy.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/IgnoreUndeployLegacyClusteredSessionNotificationPolicy.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/IgnoreUndeployLegacyClusteredSessionNotificationPolicy.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.web.tomcat.service.session.notification;
+
+/**
+ * Does not allow invocation of HttpSessionListener or HttpSessionAttributeListener
+ * during session expiration due to undeploy.
+ *
+ * @author Brian Stansberry
+ */
+public class IgnoreUndeployLegacyClusteredSessionNotificationPolicy
+ extends LegacyClusteredSessionNotificationPolicy
+{
+ /**
+ * Overrides superclass to return <code>false</code> if the cause of the
+ * notification is {@link ClusteredSessionNotificationCause.UNDEPLOY}.
+ *
+ * @return <code>true</code> if <code>status.isLocallyUsed()</code>
+ * is <code>true</code> and the cause of the notification is not
+ * {@link ClusteredSessionNotificationCause.UNDEPLOY}.
+ */
+ public boolean isHttpSessionAttributeListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName, boolean local)
+ {
+ return !ClusteredSessionNotificationCause.UNDEPLOY.equals(cause)
+ && super.isHttpSessionAttributeListenerInvocationAllowed(status, cause, attributeName, local);
+ }
+
+ /**
+ * Overrides superclass to return <code>false</code> if the cause of the
+ * notification is {@link ClusteredSessionNotificationCause.UNDEPLOY}.
+ *
+ * @return <code>true</code> if <code>status.isLocallyUsed()</code>
+ * is <code>true</code> and the cause of the notification is not
+ * {@link ClusteredSessionNotificationCause.UNDEPLOY}.
+ */
+ public boolean isHttpSessionListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, boolean local)
+ {
+ return !ClusteredSessionNotificationCause.UNDEPLOY.equals(cause)
+ && isHttpSessionListenerInvocationAllowed(status, cause, local);
+ }
+
+}
Added: trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/LegacyClusteredSessionNotificationPolicy.java
===================================================================
--- trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/LegacyClusteredSessionNotificationPolicy.java (rev 0)
+++ trunk/tomcat/src/main/org/jboss/web/tomcat/service/session/notification/LegacyClusteredSessionNotificationPolicy.java 2008-10-16 23:12:00 UTC (rev 79611)
@@ -0,0 +1,87 @@
+/*
+ * 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.notification;
+
+/**
+ * {@link ClusteredSessionNotificationPolicy} implementation that
+ * describes the behavior of JBoss AS releases prior to 4.2.4.
+ *
+ * @author Brian Stansberry
+ */
+public class LegacyClusteredSessionNotificationPolicy
+ extends ClusteredSessionNotificationPolicyBase
+ implements ClusteredSessionNotificationPolicy
+{
+ // -------------------------------------- ClusteredSessionNotificationPolicy
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return <code>true</code> if <code>status.isLocallyUsed()</code>
+ * is <code>true</code>.
+ */
+ public boolean isHttpSessionAttributeListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName, boolean local)
+ {
+ return status.isLocallyUsed();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return <code>true</code> if <code>status.isLocallyUsed()</code>
+ * is <code>true</code>.
+ */
+ public boolean isHttpSessionBindingListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName, boolean local)
+ {
+ return status.isLocallyUsed();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return <code>true</code> if <code>status.isLocallyUsed()</code>
+ * is <code>true</code>.
+ */
+ public boolean isHttpSessionListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, boolean local)
+ {
+ return status.isLocallyUsed() && !ClusteredSessionNotificationCause.FAILOVER.equals(cause);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return <code>true</code> if <code>status.isLocallyUsed()</code>
+ * is <code>true</code>.
+ */
+ public boolean isHttpSessionActivationListenerInvocationAllowed(ClusteredSessionManagementStatus status,
+ ClusteredSessionNotificationCause cause, String attributeName)
+ {
+ return status.isLocallyUsed();
+ }
+
+
+
+}
More information about the jboss-cvs-commits
mailing list