From cb09abe8737e17bd2afa4d68b3b5f2f163d53552 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 10 Jun 2020 18:40:19 +0200 Subject: [PATCH] Issue #4920 Restore ability to invalidate sessions on shutdown (#4933) Signed-off-by: Jan Bartel --- .../etc/sessions/session-cache-hash.xml | 1 + .../config/modules/session-cache-hash.mod | 1 + .../config/modules/session-cache-null.mod | 2 +- .../server/session/AbstractSessionCache.java | 18 +++ .../session/AbstractSessionCacheFactory.java | 26 ++++ .../server/session/DefaultSessionCache.java | 37 ++--- .../session/DefaultSessionCacheFactory.java | 10 +- .../session/DefaultSessionIdManager.java | 4 +- .../session/NullSessionCacheFactory.java | 21 ++- .../jetty/server/session/SessionCache.java | 9 ++ .../session/AbstractSessionCacheTest.java | 126 ++++++++++++++++-- .../session/DefaultSessionCacheTest.java | 63 +++++++-- .../server/session/NullSessionCacheTest.java | 71 ++++------ 13 files changed, 287 insertions(+), 102 deletions(-) diff --git a/jetty-server/src/main/config/etc/sessions/session-cache-hash.xml b/jetty-server/src/main/config/etc/sessions/session-cache-hash.xml index 43e4b09a280..beb537dc674 100644 --- a/jetty-server/src/main/config/etc/sessions/session-cache-hash.xml +++ b/jetty-server/src/main/config/etc/sessions/session-cache-hash.xml @@ -14,6 +14,7 @@ + diff --git a/jetty-server/src/main/config/modules/session-cache-hash.mod b/jetty-server/src/main/config/modules/session-cache-hash.mod index 2d336bc1d99..b3948efc84b 100644 --- a/jetty-server/src/main/config/modules/session-cache-hash.mod +++ b/jetty-server/src/main/config/modules/session-cache-hash.mod @@ -23,3 +23,4 @@ etc/sessions/session-cache-hash.xml #jetty.session.saveOnCreate=false #jetty.session.removeUnloadableSessions=false #jetty.session.flushOnResponseCommit=false +#jetty.session.invalidateOnShutdown=false diff --git a/jetty-server/src/main/config/modules/session-cache-null.mod b/jetty-server/src/main/config/modules/session-cache-null.mod index 2a94f59cb82..a9bb45d048a 100644 --- a/jetty-server/src/main/config/modules/session-cache-null.mod +++ b/jetty-server/src/main/config/modules/session-cache-null.mod @@ -18,4 +18,4 @@ etc/sessions/session-cache-null.xml [ini-template] #jetty.session.saveOnCreate=false #jetty.session.removeUnloadableSessions=false -#jetty.session.flushOnResponseCommit=false +#jetty.session.flushOnResponseCommit=false \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java index d684ad13dce..651e4e41a46 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCache.java @@ -99,6 +99,12 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements * a dirty session will be flushed to the session store. */ protected boolean _flushOnResponseCommit; + + /** + * If true, when the server shuts down, all sessions in the + * cache will be invalidated before being removed. + */ + protected boolean _invalidateOnShutdown; /** * Create a new Session object from pre-existing session data @@ -815,6 +821,18 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements _saveOnInactiveEviction = saveOnEvict; } + @Override + public void setInvalidateOnShutdown(boolean invalidateOnShutdown) + { + _invalidateOnShutdown = invalidateOnShutdown; + } + + @Override + public boolean isInvalidateOnShutdown() + { + return _invalidateOnShutdown; + } + /** * Whether we should save a session that has been inactive before * we boot it from the cache. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCacheFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCacheFactory.java index 6f1c21cfeb1..35209d68601 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCacheFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionCacheFactory.java @@ -31,6 +31,19 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory boolean _saveOnCreate; boolean _removeUnloadableSessions; boolean _flushOnResponseCommit; + boolean _invalidateOnShutdown; + + public abstract SessionCache newSessionCache(SessionHandler handler); + + public boolean isInvalidateOnShutdown() + { + return _invalidateOnShutdown; + } + + public void setInvalidateOnShutdown(boolean invalidateOnShutdown) + { + _invalidateOnShutdown = invalidateOnShutdown; + } /** * @return the flushOnResponseCommit @@ -111,4 +124,17 @@ public abstract class AbstractSessionCacheFactory implements SessionCacheFactory { _saveOnInactiveEvict = saveOnInactiveEvict; } + + @Override + public SessionCache getSessionCache(SessionHandler handler) + { + SessionCache cache = newSessionCache(handler); + cache.setEvictionPolicy(getEvictionPolicy()); + cache.setSaveOnInactiveEviction(isSaveOnInactiveEvict()); + cache.setSaveOnCreate(isSaveOnCreate()); + cache.setRemoveUnloadableSessions(isRemoveUnloadableSessions()); + cache.setFlushOnResponseCommit(isFlushOnResponseCommit()); + cache.setInvalidateOnShutdown(isInvalidateOnShutdown()); + return cache; + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java index 312ad50b682..c2e3306514a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java @@ -132,29 +132,18 @@ public class DefaultSessionCache extends AbstractSessionCache @Override public void shutdown() { + if (LOG.isDebugEnabled()) + LOG.debug("Shutdown sessions, invalidating = {}", isInvalidateOnShutdown()); + // loop over all the sessions in memory (a few times if necessary to catch sessions that have been // added while we're running int loop = 100; + while (!_sessions.isEmpty() && loop-- > 0) { for (Session session : _sessions.values()) { - //if we have a backing store so give the session to it to write out if necessary - if (_sessionDataStore != null) - { - session.willPassivate(); - try - { - _sessionDataStore.store(session.getId(), session.getSessionData()); - } - catch (Exception e) - { - LOG.warn(e); - } - doDelete(session.getId()); //remove from memory - session.setResident(false); - } - else + if (isInvalidateOnShutdown()) { //not preserving sessions on exit try @@ -166,6 +155,22 @@ public class DefaultSessionCache extends AbstractSessionCache LOG.ignore(e); } } + else + { + //write out the session and remove from the cache + if (_sessionDataStore.isPassivating()) + session.willPassivate(); + try + { + _sessionDataStore.store(session.getId(), session.getSessionData()); + } + catch (Exception e) + { + LOG.warn(e); + } + doDelete(session.getId()); //remove from memory + session.setResident(false); + } } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java index c9cb283a34c..ab81f870d6a 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCacheFactory.java @@ -26,14 +26,8 @@ package org.eclipse.jetty.server.session; public class DefaultSessionCacheFactory extends AbstractSessionCacheFactory { @Override - public SessionCache getSessionCache(SessionHandler handler) + public SessionCache newSessionCache(SessionHandler handler) { - DefaultSessionCache cache = new DefaultSessionCache(handler); - cache.setEvictionPolicy(getEvictionPolicy()); - cache.setSaveOnInactiveEviction(isSaveOnInactiveEvict()); - cache.setSaveOnCreate(isSaveOnCreate()); - cache.setRemoveUnloadableSessions(isRemoveUnloadableSessions()); - cache.setFlushOnResponseCommit(isFlushOnResponseCommit()); - return cache; + return new DefaultSessionCache(handler); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java index 5618f9c7d80..d3a5db08bf9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java @@ -485,7 +485,9 @@ public class DefaultSessionIdManager extends ContainerLifeCycle implements Sessi { for (Handler h : tmp) { - if (h.isStarted()) + //This method can be called on shutdown when the handlers are STOPPING, so only + //check that they are not already stopped + if (!h.isStopped() && !h.isFailed()) handlers.add((SessionHandler)h); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java index cf15a4a974e..eefd6302e25 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/NullSessionCacheFactory.java @@ -55,14 +55,23 @@ public class NullSessionCacheFactory extends AbstractSessionCacheFactory if (LOG.isDebugEnabled()) LOG.debug("Ignoring eviction policy setting for NullSessionCaches"); } + + @Override + public boolean isInvalidateOnShutdown() + { + return false; //meaningless for NullSessionCache + } @Override - public SessionCache getSessionCache(SessionHandler handler) + public void setInvalidateOnShutdown(boolean invalidateOnShutdown) { - NullSessionCache cache = new NullSessionCache(handler); - cache.setSaveOnCreate(isSaveOnCreate()); - cache.setRemoveUnloadableSessions(isRemoveUnloadableSessions()); - cache.setFlushOnResponseCommit(isFlushOnResponseCommit()); - return cache; + if (LOG.isDebugEnabled()) + LOG.debug("Ignoring invalidateOnShutdown setting for NullSessionCaches"); + } + + @Override + public SessionCache newSessionCache(SessionHandler handler) + { + return new NullSessionCache(handler); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionCache.java index 734c6a15097..f2600c2dd25 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionCache.java @@ -312,4 +312,13 @@ public interface SessionCache extends LifeCycle * before the response is committed. */ boolean isFlushOnResponseCommit(); + + /** + * If true, all existing sessions in the cache will be invalidated when + * the server shuts down. Default is false. + * @param invalidateOnShutdown + */ + void setInvalidateOnShutdown(boolean invalidateOnShutdown); + + boolean isInvalidateOnShutdown(); } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AbstractSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AbstractSessionCacheTest.java index 3ecbb505d90..246946444f5 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AbstractSessionCacheTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/AbstractSessionCacheTest.java @@ -20,9 +20,7 @@ package org.eclipse.jetty.server.session; import java.util.Collections; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; @@ -119,11 +117,25 @@ public abstract class AbstractSessionCacheTest ++activateCalls; } } - - public abstract AbstractSessionCacheFactory newSessionCacheFactory(int evictionPolicy, boolean saveOnCreate, - boolean saveOnInactiveEvict, boolean removeUnloadableSessions, + + public abstract AbstractSessionCacheFactory newSessionCacheFactory(int evictionPolicy, + boolean saveOnCreate, + boolean saveOnInactiveEvict, + boolean removeUnloadableSessions, boolean flushOnResponseCommit); + public abstract void checkSessionBeforeShutdown(String id, + SessionDataStore store, + SessionCache cache, + TestSessionActivationListener activationListener, + TestHttpSessionListener sessionListener) throws Exception; + + public abstract void checkSessionAfterShutdown(String id, + SessionDataStore store, + SessionCache cache, + TestSessionActivationListener activationListener, + TestHttpSessionListener sessionListener) throws Exception; + /** * Test that a session that exists in the datastore, but that cannot be * read will be invalidated and deleted, and thus a request to re-use that @@ -243,11 +255,14 @@ public abstract class AbstractSessionCacheTest assertEquals(now - 20, session.getCreationTime()); } + /** + * Test state of session with call to commit + * + * @throws Exception + */ @Test public void testCommit() throws Exception { - //Test state of session with call to commit - Server server = new Server(); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); @@ -320,11 +335,14 @@ public abstract class AbstractSessionCacheTest commitAndCheckSaveState(cache, store, session, false, true, false, true, 0, 0); } + /** + * Test what happens with various states of a session when commit + * is called before release + * @throws Exception + */ @Test public void testCommitAndRelease() throws Exception { - //test what happens with various states of a session when commit - //is called before release Server server = new Server(); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); @@ -421,7 +439,7 @@ public abstract class AbstractSessionCacheTest assertFalse(session.getSessionData().isDirty()); assertTrue(session.getSessionData().isMetaDataDirty()); } - + /** * Test the exist method. */ @@ -596,6 +614,92 @@ public abstract class AbstractSessionCacheTest cache.newSession(null, "1234", now, TimeUnit.MINUTES.toMillis(10)); assertFalse(store.exists("1234")); } + + /** + * Test shutting down the server with invalidateOnShutdown==false + * + * @throws Exception + */ + @Test + public void testNoInvalidateOnShutdown() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + server.setHandler(context); + + AbstractSessionCacheFactory cacheFactory = newSessionCacheFactory(SessionCache.NEVER_EVICT, false, false, false, false); + SessionCache cache = cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(true);//fake passivation + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + TestHttpSessionListener sessionListener = new TestHttpSessionListener(); + context.getSessionHandler().addEventListener(sessionListener); + + server.start(); + + //put a session in the cache and store + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now - 20, now - 10, now - 20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + TestSessionActivationListener activationListener = new TestSessionActivationListener(); + cache.add("1234", session); + session.setAttribute("aaa", activationListener); + cache.release("1234", session); + checkSessionBeforeShutdown("1234", store, cache, activationListener, sessionListener); + + server.stop(); //calls shutdown + + checkSessionAfterShutdown("1234", store, cache, activationListener, sessionListener); + } + + /** + * Test shutdown of the server with invalidateOnShutdown==true + * @throws Exception + */ + @Test + public void testInvalidateOnShutdown() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + server.setHandler(context); + + //flushOnResponseCommit is true + AbstractSessionCacheFactory cacheFactory = newSessionCacheFactory(SessionCache.NEVER_EVICT, false, false, false, true); + cacheFactory.setInvalidateOnShutdown(true); + SessionCache cache = cacheFactory.getSessionCache(context.getSessionHandler()); + + + TestSessionDataStore store = new TestSessionDataStore(true); //fake a passivating store + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + TestHttpSessionListener sessionListener = new TestHttpSessionListener(); + context.getSessionHandler().addEventListener(sessionListener); + + server.start(); + + //Make a session in the store and cache and check that it is invalidated on shutdown + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("8888", now - 20, now - 10, now - 20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + cache.add("8888", session); + + TestSessionActivationListener activationListener = new TestSessionActivationListener(); + session.setAttribute("aaa", activationListener); + cache.release("8888", session); + checkSessionBeforeShutdown("8888", store, cache, activationListener, sessionListener); + + server.stop(); + + checkSessionAfterShutdown("8888", store, cache, activationListener, sessionListener); + } public void commitAndCheckSaveState(SessionCache cache, TestSessionDataStore store, Session session, boolean expectedBeforeDirty, boolean expectedBeforeMetaDirty, @@ -611,7 +715,7 @@ public abstract class AbstractSessionCacheTest assertEquals(expectedAfterMetaDirty, session.getSessionData().isMetaDataDirty()); assertEquals(expectedAfterNumSaves, store._numSaves.get()); } - + public Session createUnExpiredSession(SessionCache cache, SessionDataStore store, String id) { long now = System.currentTimeMillis(); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java index 3d2624ddddd..2785acbcef6 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.server.session; import java.util.Random; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpSession; import org.eclipse.jetty.server.Request; @@ -54,6 +53,42 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest factory.setFlushOnResponseCommit(flushOnResponseCommit); return factory; } + + @Override + public void checkSessionBeforeShutdown(String id, + SessionDataStore store, + SessionCache cache, + TestSessionActivationListener activationListener, + TestHttpSessionListener sessionListener) throws Exception + { + assertTrue(store.exists(id)); + assertTrue(cache.contains(id)); + assertFalse(sessionListener.destroyedSessions.contains(id)); + assertEquals(1, activationListener.passivateCalls); + assertEquals(1, activationListener.activateCalls); + } + + @Override + public void checkSessionAfterShutdown(String id, + SessionDataStore store, + SessionCache cache, + TestSessionActivationListener activationListener, + TestHttpSessionListener sessionListener) throws Exception + { + if (cache.isInvalidateOnShutdown()) + { + assertFalse(store.exists(id)); + assertFalse(cache.contains(id)); + assertTrue(sessionListener.destroyedSessions.contains(id)); + } + else + { + assertTrue(store.exists(id)); + assertFalse(cache.contains(id)); + assertEquals(2, activationListener.passivateCalls); + assertEquals(1, activationListener.activateCalls); //no re-activate on shutdown + } + } @Test public void testRenewWithInvalidate() throws Exception @@ -182,25 +217,26 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest /** * Test sessions are saved when shutdown with a store. */ - @Test - public void testShutdownWithSessionStore() + /* @Test + public void testNoInvalidateOnShutdown() throws Exception { Server server = new Server(); - + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/test"); context.setServer(server); - + server.setHandler(context); + AbstractSessionCacheFactory cacheFactory = newSessionCacheFactory(SessionCache.NEVER_EVICT, false, false, false, false); DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); - + TestSessionDataStore store = new TestSessionDataStore(true);//fake passivation cache.setSessionDataStore(store); context.getSessionHandler().setSessionCache(cache); - - context.start(); - + + server.start(); + //put a session in the cache and store long now = System.currentTimeMillis(); SessionData data = store.newSessionData("1234", now - 20, now - 10, now - 20, TimeUnit.MINUTES.toMillis(10)); @@ -210,17 +246,18 @@ public class DefaultSessionCacheTest extends AbstractSessionCacheTest assertTrue(cache.contains("1234")); session.setAttribute("aaa", listener); cache.release("1234", session); - + assertTrue(store.exists("1234")); assertTrue(cache.contains("1234")); - - context.stop(); //calls shutdown - + + server.stop(); //calls shutdown + assertTrue(store.exists("1234")); assertFalse(cache.contains("1234")); assertEquals(2, listener.passivateCalls); assertEquals(1, listener.activateCalls); } + */ /** * Test that a session id can be renewed. diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java index 5430cffd2f3..acae37f7986 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NullSessionCacheTest.java @@ -45,54 +45,33 @@ public class NullSessionCacheTest extends AbstractSessionCacheTest factory.setFlushOnResponseCommit(flushOnResponseCommit); return factory; } - - @Test - public void testShutdownWithSessionStore() - throws Exception + + @Override + public void checkSessionBeforeShutdown(String id, + SessionDataStore store, + SessionCache cache, + TestSessionActivationListener activationListener, + TestHttpSessionListener sessionListener) throws Exception { - Server server = new Server(); + assertFalse(cache.contains(id)); //NullSessionCache never caches + assertTrue(store.exists(id)); + assertFalse(sessionListener.destroyedSessions.contains(id)); + assertEquals(1, activationListener.passivateCalls); + assertEquals(0, activationListener.activateCalls); //NullSessionCache always evicts on release, so never reactivates + } - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/test"); - context.setServer(server); - - AbstractSessionCacheFactory cacheFactory = newSessionCacheFactory(SessionCache.NEVER_EVICT, false, false, false, false); - SessionCache cache = cacheFactory.getSessionCache(context.getSessionHandler()); - - TestSessionDataStore store = new TestSessionDataStore(true);//fake passivation - cache.setSessionDataStore(store); - context.getSessionHandler().setSessionCache(cache); - - context.start(); - - //put a session in the cache and store - long now = System.currentTimeMillis(); - SessionData data = store.newSessionData("1234", now - 20, now - 10, now - 20, TimeUnit.MINUTES.toMillis(10)); - Session session = cache.newSession(data); - TestSessionActivationListener listener = new TestSessionActivationListener(); - cache.add("1234", session); - //cache never contains the session - assertFalse(cache.contains("1234")); - session.setAttribute("aaa", listener); - //write session out on release - cache.release("1234", session); - assertEquals(1, store._numSaves.get()); - assertEquals(1, listener.passivateCalls); - assertEquals(0, listener.activateCalls); //NullSessionCache always evicts on release, so never reactivates - - assertTrue(store.exists("1234")); - //cache never contains session - assertFalse(cache.contains("1234")); - - context.stop(); //calls shutdown - - //session should still exist in store - assertTrue(store.exists("1234")); - //cache never contains the session - assertFalse(cache.contains("1234")); - //shutdown does not save session - assertEquals(1, listener.passivateCalls); - assertEquals(0, listener.activateCalls); + @Override + public void checkSessionAfterShutdown(String id, + SessionDataStore store, + SessionCache cache, + TestSessionActivationListener activationListener, + TestHttpSessionListener sessionListener) throws Exception + { + assertFalse(cache.contains(id)); //NullSessionCache never caches + assertTrue(store.exists(id)); //NullSessionCache doesn't do anything on shutdown + assertFalse(sessionListener.destroyedSessions.contains(id)); //NullSessionCache does nothing on shutdown + assertEquals(1, activationListener.passivateCalls); + assertEquals(0, activationListener.activateCalls); //NullSessionCache always evicts on release, so never reactivates } @Test