diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 04141df0596..8be5b3f42a3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -2877,7 +2877,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override public int getSessionTimeout() { - // TODO new in 4.0 LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "getSessionTimeout()"); return 0; } @@ -2888,7 +2887,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override public void setSessionTimeout(int sessionTimeout) { - // TODO new in 4.0 LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "setSessionTimeout(int)"); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index 03acb067f6b..9da228dac54 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -133,14 +133,7 @@ public class SessionHandler extends ScopedHandler HttpSessionIdListener.class, HttpSessionListener.class }; - - /** - * Web.xml session-timeout is set in minutes, but is stored as an int in seconds by HttpSession and - * the sessionmanager. Thus MAX_INT is the max number of seconds that can be set, and MAX_INT/60 is the - * max number of minutes that you can set. - */ - public static final java.math.BigDecimal MAX_INACTIVE_MINUTES = new java.math.BigDecimal(Integer.MAX_VALUE / 60); - + @Deprecated(since = "Servlet API 2.1") static final HttpSessionContext __nullSessionContext = new HttpSessionContext() { @@ -159,7 +152,7 @@ public class SessionHandler extends ScopedHandler return Collections.enumeration(Collections.EMPTY_LIST); } }; - + /** * Setting of max inactive interval for new sessions * -1 means no timeout diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index b2b5fa7f3be..632ca6da208 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -29,6 +29,8 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; + import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterRegistration; @@ -1410,6 +1412,42 @@ public class ServletContextHandler extends ContextHandler _sessionHandler.setSessionTrackingModes(sessionTrackingModes); } + @Override + public int getSessionTimeout() + { + if (!isStarting()) + throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + + int timeout = -1; + if (_sessionHandler != null) + { + timeout = _sessionHandler.getMaxInactiveInterval(); + } + + return (int)TimeUnit.SECONDS.toMinutes(timeout); + } + + @Override + public void setSessionTimeout(int sessionTimeout) + { + if (!isStarting()) + throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + + if (_sessionHandler != null) + { + long tmp = TimeUnit.MINUTES.toSeconds(sessionTimeout); + if (tmp > Integer.MAX_VALUE) + tmp = Integer.MAX_VALUE; + if (tmp < Integer.MIN_VALUE) + tmp = Integer.MIN_VALUE; + _sessionHandler.setMaxInactiveInterval((int)tmp); + } + } + @Override public void addListener(String className) { diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java index e86dc9aad1d..6d8a75f8bf7 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletContextHandlerTest.java @@ -109,6 +109,20 @@ public class ServletContextHandlerTest public static class MySCI implements ServletContainerInitializer { + boolean callSessionTimeouts; + int timeout; + + public MySCI(boolean callSessionTimeouts, int timeout) + { + this.callSessionTimeouts = callSessionTimeouts; + this.timeout = timeout; + } + + public MySCI() + { + this(false, -1); + } + @Override public void onStartup(Set> c, ServletContext ctx) throws ServletException { @@ -116,7 +130,20 @@ public class ServletContextHandlerTest if (ctx.getAttribute("MySCI.startup") != null) throw new IllegalStateException("MySCI already called"); ctx.setAttribute("MySCI.startup", Boolean.TRUE); - ctx.addListener(new MyContextListener()); + ctx.addListener(new MyContextListener(callSessionTimeouts, timeout)); + if (callSessionTimeouts) + { + try + { + ctx.setSessionTimeout(timeout); + ctx.setAttribute("MYSCI.setSessionTimeout", Boolean.TRUE); + ctx.setAttribute("MYSCI.getSessionTimeout", Integer.valueOf(ctx.getSessionTimeout())); + } + catch (Exception e) + { + ctx.setAttribute("MYSCI.sessionTimeoutFailure", e); + } + } } } @@ -143,12 +170,50 @@ public class ServletContextHandlerTest public static class MyContextListener implements ServletContextListener { - + boolean callSessionTimeouts; + int timeout; + + public MyContextListener(boolean callSessionTimeouts, int timeout) + { + this.callSessionTimeouts = callSessionTimeouts; + this.timeout = timeout; + } + + public MyContextListener() + { + this(false, -1); + } + @Override public void contextInitialized(ServletContextEvent sce) { assertNull(sce.getServletContext().getAttribute("MyContextListener.contextInitialized")); sce.getServletContext().setAttribute("MyContextListener.contextInitialized", Boolean.TRUE); + + if (callSessionTimeouts) + { + try + { + sce.getServletContext().setSessionTimeout(timeout); + sce.getServletContext().setAttribute("MyContextListener.setSessionTimeout", Boolean.FALSE); + } + catch (UnsupportedOperationException e) + { + //Should NOT be able to call setSessionTimeout from this SCL + sce.getServletContext().setAttribute("MyContextListener.setSessionTimeout", Boolean.TRUE); + } + + try + { + sce.getServletContext().getSessionTimeout(); + sce.getServletContext().setAttribute("MyContextListener.getSessionTimeout", Boolean.FALSE); + } + catch (UnsupportedOperationException e) + { + //Should NOT be able to call getSessionTimeout from this SCL + sce.getServletContext().setAttribute("MyContextListener.getSessionTimeout", Boolean.TRUE); + } + } } @Override @@ -404,6 +469,28 @@ public class ServletContextHandlerTest _server.stop(); _server.join(); } + + @Test + public void testGetSetSessionTimeout() throws Exception + { + ContextHandlerCollection contexts = new ContextHandlerCollection(); + _server.setHandler(contexts); + + Integer timeout = Integer.valueOf(100); + ServletContextHandler root = new ServletContextHandler(contexts, "/", ServletContextHandler.SESSIONS); + root.addBean(new MySCIStarter(root.getServletContext(), new MySCI(true, timeout.intValue())), true); + _server.start(); + + //test can set session timeout from ServletContainerInitializer + assertTrue((Boolean)root.getServletContext().getAttribute("MYSCI.setSessionTimeout")); + //test can get session timeout from ServletContainerInitializer + assertEquals(timeout, (Integer)root.getServletContext().getAttribute("MYSCI.getSessionTimeout")); + assertNull(root.getAttribute("MYSCI.sessionTimeoutFailure")); + //test can't get session timeout from ContextListener that is not from annotation or web.xml + assertTrue((Boolean)root.getServletContext().getAttribute("MyContextListener.getSessionTimeout")); + //test can't set session timeout from ContextListener that is not from annotation or web.xml + assertTrue((Boolean)root.getServletContext().getAttribute("MyContextListener.setSessionTimeout")); + } @Test public void testAddSessionListener() throws Exception diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java index 8c7cef789a6..bf83e33bf55 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -30,6 +30,8 @@ import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.concurrent.TimeUnit; + import javax.servlet.DispatcherType; import javax.servlet.MultipartConfigElement; import javax.servlet.SessionTrackingMode; @@ -650,11 +652,11 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor XmlParser.Node tNode = node.get("session-timeout"); if (tNode != null) { - java.math.BigDecimal asDecimal = new java.math.BigDecimal(tNode.toString(false, true)); - if (asDecimal.compareTo(org.eclipse.jetty.server.session.SessionHandler.MAX_INACTIVE_MINUTES) > 0) - throw new IllegalStateException("Max session-timeout in minutes is " + org.eclipse.jetty.server.session.SessionHandler.MAX_INACTIVE_MINUTES); - - context.getSessionHandler().setMaxInactiveInterval(asDecimal.intValueExact() * 60); + long val = Long.parseLong(tNode.toString(false, true)); + val = TimeUnit.MINUTES.toSeconds(val); + if (val > Integer.MAX_VALUE) + throw new IllegalStateException("Max session-timeout in minutes is " + TimeUnit.SECONDS.toMinutes(Integer.MAX_VALUE)); + context.getServletContext().setSessionTimeout((int)val); } //Servlet Spec 3.0 diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotatedListener.java b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotatedListener.java index 9b97baffee3..241cdde622c 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotatedListener.java +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotatedListener.java @@ -107,6 +107,29 @@ public class AnnotatedListener implements HttpSessionListener, HttpSessionAttrib throw new IllegalStateException("AnnotatedListener already initialized"); sce.getServletContext().setAttribute("com.acme.AnnotationTest.sclInjectWebListenerTest", Boolean.valueOf(maxAmount != null)); + + boolean setSessionTimeout; + try + { + sce.getServletContext().setSessionTimeout(180); + setSessionTimeout = true; + } + catch (Exception e) + { + setSessionTimeout = false; + } + sce.getServletContext().setAttribute("com.acme.AnnotationTest.sclSetSessionTimeout", Boolean.valueOf(setSessionTimeout)); + + boolean getSessionTimeout; + try + { + getSessionTimeout = (sce.getServletContext().getSessionTimeout() == 180); + } + catch (Exception e) + { + getSessionTimeout = false; + } + sce.getServletContext().setAttribute("com.acme.AnnotationTest.sclGetSessionTimeout", Boolean.valueOf(getSessionTimeout)); } public void requestCompleted(ServletRequestEvent rre) diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotationTest.java b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotationTest.java index f58c71a6a41..e9c576edf60 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotationTest.java +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/java/com/acme/test/AnnotationTest.java @@ -275,6 +275,12 @@ public class AnnotationTest extends HttpServlet Boolean annotatedListenerInject = (Boolean)config.getServletContext().getAttribute("com.acme.AnnotationTest.sclInjectWebListenerTest"); out.println("

Result: " + (annotatedListenerInject.booleanValue() ? "PASS" : "FAIL") + "

"); + out.println("

ServletContextListener as @WebListener Get/Set Session Timeout

"); + out.println("

getSessionTimeout Result: " + + ((Boolean)config.getServletContext().getAttribute("com.acme.AnnotationTest.sclGetSessionTimeout") ? "PASS" : "FAIL") + "

"); + out.println("

setSessionTimeout Result: " + + ((Boolean)config.getServletContext().getAttribute("com.acme.AnnotationTest.sclSetSessionTimeout") ? "PASS" : "FAIL") + "

"); + out.println("

Programmatic Listener Injected

"); Boolean programListenerInject = (Boolean)config.getServletContext().getAttribute("com.acme.AnnotationTest.programListenerInjectTest"); out.println("

Result: " + (programListenerInject.booleanValue() ? "PASS" : "FAIL") + "

");