* Issue #6277 Better handling of exceptions thrown in sessionDestroyed Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
parent
edcaf70d9a
commit
087f486b44
|
@ -498,10 +498,7 @@ public class Session implements SessionHandler.SessionIf
|
||||||
{
|
{
|
||||||
try (Lock lock = _lock.lock())
|
try (Lock lock = _lock.lock())
|
||||||
{
|
{
|
||||||
if (isInvalid())
|
checkValidForRead();
|
||||||
{
|
|
||||||
throw new IllegalStateException("Session not valid");
|
|
||||||
}
|
|
||||||
return _sessionData.getLastAccessed();
|
return _sessionData.getLastAccessed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -947,14 +944,18 @@ public class Session implements SessionHandler.SessionIf
|
||||||
// do the invalidation
|
// do the invalidation
|
||||||
_handler.callSessionDestroyedListeners(this);
|
_handler.callSessionDestroyedListeners(this);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn("Error during Session destroy listener", e);
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
// call the attribute removed listeners and finally mark it
|
// call the attribute removed listeners and finally mark it
|
||||||
// as invalid
|
// as invalid
|
||||||
finishInvalidate();
|
finishInvalidate();
|
||||||
|
// tell id mgr to remove sessions with same id from all contexts
|
||||||
|
_handler.getSessionIdManager().invalidateAll(_sessionData.getId());
|
||||||
}
|
}
|
||||||
// tell id mgr to remove sessions with same id from all contexts
|
|
||||||
_handler.getSessionIdManager().invalidateAll(_sessionData.getId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -31,16 +31,18 @@ public class TestHttpSessionListener implements HttpSessionListener
|
||||||
public List<String> createdSessions = new ArrayList<>();
|
public List<String> createdSessions = new ArrayList<>();
|
||||||
public List<String> destroyedSessions = new ArrayList<>();
|
public List<String> destroyedSessions = new ArrayList<>();
|
||||||
public boolean accessAttribute = false;
|
public boolean accessAttribute = false;
|
||||||
public Exception ex = null;
|
public boolean lastAccessTime = false;
|
||||||
|
public Exception attributeException = null;
|
||||||
|
public Exception accessTimeException = null;
|
||||||
|
|
||||||
public TestHttpSessionListener(boolean access)
|
public TestHttpSessionListener(boolean accessAttribute, boolean lastAccessTime)
|
||||||
{
|
{
|
||||||
accessAttribute = access;
|
this.accessAttribute = accessAttribute;
|
||||||
|
this.lastAccessTime = lastAccessTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestHttpSessionListener()
|
public TestHttpSessionListener()
|
||||||
{
|
{
|
||||||
accessAttribute = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sessionDestroyed(HttpSessionEvent se)
|
public void sessionDestroyed(HttpSessionEvent se)
|
||||||
|
@ -54,7 +56,19 @@ public class TestHttpSessionListener implements HttpSessionListener
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
ex = e;
|
attributeException = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastAccessTime)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
se.getSession().getLastAccessedTime();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
accessTimeException = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,9 @@ public class TestHttpSessionListenerWithWebappClasses extends TestHttpSessionLis
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestHttpSessionListenerWithWebappClasses(boolean access)
|
public TestHttpSessionListenerWithWebappClasses(boolean attribute, boolean lastAccessTime)
|
||||||
{
|
{
|
||||||
super(access);
|
super(attribute, lastAccessTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,7 +52,7 @@ public class TestHttpSessionListenerWithWebappClasses extends TestHttpSessionLis
|
||||||
}
|
}
|
||||||
catch (Exception cnfe)
|
catch (Exception cnfe)
|
||||||
{
|
{
|
||||||
ex = cnfe;
|
attributeException = cnfe;
|
||||||
}
|
}
|
||||||
super.sessionDestroyed(se);
|
super.sessionDestroyed(se);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.hamcrest.Matchers.in;
|
import static org.hamcrest.Matchers.in;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
@ -92,7 +93,7 @@ public class SessionListenerTest
|
||||||
TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
|
TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
|
||||||
cacheFactory, storeFactory);
|
cacheFactory, storeFactory);
|
||||||
ServletContextHandler context = server.addContext(contextPath);
|
ServletContextHandler context = server.addContext(contextPath);
|
||||||
TestHttpSessionListener listener = new TestHttpSessionListener(true);
|
TestHttpSessionListener listener = new TestHttpSessionListener(true, true);
|
||||||
context.getSessionHandler().addEventListener(listener);
|
context.getSessionHandler().addEventListener(listener);
|
||||||
TestServlet servlet = new TestServlet();
|
TestServlet servlet = new TestServlet();
|
||||||
ServletHolder holder = new ServletHolder(servlet);
|
ServletHolder holder = new ServletHolder(servlet);
|
||||||
|
@ -136,6 +137,72 @@ public class SessionListenerTest
|
||||||
LifeCycle.stop(server);
|
LifeCycle.stop(server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that if a session listener throws an exception during sessionDestroyed the session is still invalidated
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testListenerWithInvalidationException() throws Exception
|
||||||
|
{
|
||||||
|
String contextPath = "";
|
||||||
|
String servletMapping = "/server";
|
||||||
|
int inactivePeriod = 6;
|
||||||
|
int scavengePeriod = -1;
|
||||||
|
|
||||||
|
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||||
|
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
|
||||||
|
TestSessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory();
|
||||||
|
storeFactory.setGracePeriodSec(scavengePeriod);
|
||||||
|
|
||||||
|
TestServer server = new TestServer(0, inactivePeriod, scavengePeriod,
|
||||||
|
cacheFactory, storeFactory);
|
||||||
|
ServletContextHandler context = server.addContext(contextPath);
|
||||||
|
ThrowingSessionListener listener = new ThrowingSessionListener();
|
||||||
|
context.getSessionHandler().addEventListener(listener);
|
||||||
|
TestServlet servlet = new TestServlet();
|
||||||
|
ServletHolder holder = new ServletHolder(servlet);
|
||||||
|
context.addServlet(holder, servletMapping);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
server.start();
|
||||||
|
int port1 = server.getPort();
|
||||||
|
|
||||||
|
HttpClient client = new HttpClient();
|
||||||
|
client.start();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String url = "http://localhost:" + port1 + contextPath + servletMapping;
|
||||||
|
// Create the session
|
||||||
|
ContentResponse response1 = client.GET(url + "?action=init");
|
||||||
|
assertEquals(HttpServletResponse.SC_OK, response1.getStatus());
|
||||||
|
String sessionCookie = response1.getHeaders().get("Set-Cookie");
|
||||||
|
assertNotNull(sessionCookie);
|
||||||
|
assertTrue(TestServlet.bindingListener.bound);
|
||||||
|
|
||||||
|
String sessionId = TestServer.extractSessionId(sessionCookie);
|
||||||
|
|
||||||
|
// Make a request which will invalidate the existing session
|
||||||
|
Request request2 = client.newRequest(url + "?action=test");
|
||||||
|
ContentResponse response2 = request2.send();
|
||||||
|
assertEquals(HttpServletResponse.SC_OK, response2.getStatus());
|
||||||
|
|
||||||
|
assertTrue(TestServlet.bindingListener.unbound);
|
||||||
|
|
||||||
|
//check session no longer exists
|
||||||
|
assertFalse(context.getSessionHandler().getSessionCache().contains(sessionId));
|
||||||
|
assertFalse(context.getSessionHandler().getSessionCache().getSessionDataStore().exists(sessionId));
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LifeCycle.stop(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LifeCycle.stop(server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that listeners are called when a session expires
|
* Test that listeners are called when a session expires
|
||||||
|
@ -177,7 +244,7 @@ public class SessionListenerTest
|
||||||
ServletContextHandler context = server1.addContext(contextPath);
|
ServletContextHandler context = server1.addContext(contextPath);
|
||||||
context.setClassLoader(contextClassLoader);
|
context.setClassLoader(contextClassLoader);
|
||||||
context.addServlet(holder, servletMapping);
|
context.addServlet(holder, servletMapping);
|
||||||
TestHttpSessionListener listener = new TestHttpSessionListenerWithWebappClasses(true);
|
TestHttpSessionListener listener = new TestHttpSessionListenerWithWebappClasses(true, true);
|
||||||
context.getSessionHandler().addEventListener(listener);
|
context.getSessionHandler().addEventListener(listener);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -206,7 +273,8 @@ public class SessionListenerTest
|
||||||
|
|
||||||
assertThat(sessionId, is(in(listener.destroyedSessions)));
|
assertThat(sessionId, is(in(listener.destroyedSessions)));
|
||||||
|
|
||||||
assertNull(listener.ex);
|
assertNull(listener.attributeException);
|
||||||
|
assertNull(listener.accessTimeException);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -241,7 +309,7 @@ public class SessionListenerTest
|
||||||
ServletHolder holder = new ServletHolder(servlet);
|
ServletHolder holder = new ServletHolder(servlet);
|
||||||
ServletContextHandler context = server1.addContext(contextPath);
|
ServletContextHandler context = server1.addContext(contextPath);
|
||||||
context.addServlet(holder, servletMapping);
|
context.addServlet(holder, servletMapping);
|
||||||
TestHttpSessionListener listener = new TestHttpSessionListener();
|
TestHttpSessionListener listener = new TestHttpSessionListener(true, true);
|
||||||
|
|
||||||
context.getSessionHandler().addEventListener(listener);
|
context.getSessionHandler().addEventListener(listener);
|
||||||
|
|
||||||
|
@ -276,7 +344,8 @@ public class SessionListenerTest
|
||||||
|
|
||||||
assertTrue(listener.destroyedSessions.contains("1234"));
|
assertTrue(listener.destroyedSessions.contains("1234"));
|
||||||
|
|
||||||
assertNull(listener.ex);
|
assertNull(listener.attributeException);
|
||||||
|
assertNull(listener.accessTimeException);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -301,6 +370,22 @@ public class SessionListenerTest
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ThrowingSessionListener implements HttpSessionListener
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionCreated(HttpSessionEvent se)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionDestroyed(HttpSessionEvent se)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Exception during sessionDestroyed");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSessionListeners()
|
public void testSessionListeners()
|
||||||
|
|
Loading…
Reference in New Issue