From 0c20622648859d764984879a92fb10c4617b0a71 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 25 Mar 2020 11:17:05 +0100 Subject: [PATCH] Issue #4700 ServletContext.createXXX methods should throw UnsupportedOperationException (#4701) * Issue #4700 ServletContext.createXXX methods should throw UnsupportedOperationException Signed-off-by: Jan Bartel --- .../jetty/server/AsyncContextState.java | 2 +- .../jetty/server/handler/ContextHandler.java | 2 +- .../jetty/servlet/ServletContextHandler.java | 38 ++++- .../servlet/ServletContextHandlerTest.java | 132 +++++++++++++++++- 4 files changed, 170 insertions(+), 4 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java index 806b4a809f8e..a68785ef6161 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContextState.java @@ -77,7 +77,7 @@ public T createListener(Class clazz) throws Servlet { ContextHandler contextHandler = state().getContextHandler(); if (contextHandler != null) - return contextHandler.getServletContext().createListener(clazz); + return contextHandler.getServletContext().createInstance(clazz); try { return clazz.getDeclaredConstructor().newInstance(); 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 ef33e3d66b8d..26b955a89d31 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 @@ -2713,7 +2713,7 @@ public void addListener(Class listenerClass) LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "addListener(Class)"); } - protected T createInstance(Class clazz) throws ServletException + public T createInstance(Class clazz) throws ServletException { try { 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 f7c97729594f..d86529440b0f 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 @@ -1256,7 +1256,7 @@ public boolean setInitParameter(String name, String value) } @Override - protected T createInstance(Class clazz) throws ServletException + public T createInstance(Class clazz) throws ServletException { return _objFactory.decorate(super.createInstance(clazz)); } @@ -1424,6 +1424,42 @@ public void setSessionTimeout(int sessionTimeout) _sessionHandler.setMaxInactiveInterval((int)tmp); } } + + @Override + public T createServlet(Class clazz) throws ServletException + { + if (!_enabled) + throw new UnsupportedOperationException(); + return super.createServlet(clazz); + } + + @Override + public T createFilter(Class clazz) throws ServletException + { + if (!_enabled) + throw new UnsupportedOperationException(); + return super.createFilter(clazz); + } + + @Override + public T createListener(Class clazz) throws ServletException + { + if (!_enabled) + throw new UnsupportedOperationException(); + try + { + checkListener(clazz); + } + catch (IllegalArgumentException e) + { + //Bizarrely, according to the spec, it is NOT an error to create an instance of + //a ServletContextListener from inside a ServletContextListener, but it IS an error + //to call addListener with one! + if (!ServletContextListener.class.isAssignableFrom(clazz)) + throw e; + } + return super.createListener(clazz); + } @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 88d6b6133268..f7ccb0ffd2c8 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 @@ -464,6 +464,66 @@ public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) } } + /** + * ServletContextListener that is designed to be added programmatically, + * which should make all of the createListener, createServlet, createFilter + * methods fail with UnsupportedOperationException + * + */ + public class CreatingSCL implements ServletContextListener + { + @Override + public void contextInitialized(ServletContextEvent sce) + { + try + { + sce.getServletContext().createFilter(MyFilter.class); + sce.getServletContext().setAttribute("CreatingSCL.filter", Boolean.FALSE); + } + catch (UnsupportedOperationException e) + { + sce.getServletContext().setAttribute("CreatingSCL.filter", Boolean.TRUE); + } + catch (Exception e) + { + fail(e); + } + + try + { + sce.getServletContext().createServlet(HelloServlet.class); + sce.getServletContext().setAttribute("CreatingSCL.servlet", Boolean.FALSE); + } + catch (UnsupportedOperationException e) + { + sce.getServletContext().setAttribute("CreatingSCL.servlet", Boolean.TRUE); + } + catch (Exception e) + { + fail(e); + } + + try + { + sce.getServletContext().createListener(MyContextListener.class); + sce.getServletContext().setAttribute("CreatingSCL.listener", Boolean.FALSE); + } + catch (UnsupportedOperationException e) + { + sce.getServletContext().setAttribute("CreatingSCL.listener", Boolean.TRUE); + } + catch (Exception e) + { + fail(e); + } + } + + @Override + public void contextDestroyed(ServletContextEvent sce) + { + } + } + public class InitialListener implements ServletContextListener { @Override @@ -499,7 +559,7 @@ public void contextInitialized(ServletContextEvent sce) { MyContextListener contextListener = sce.getServletContext().createListener(MyContextListener.class); sce.getServletContext().addListener(contextListener); - fail("Adding SCI from an SCI!"); + fail("Adding SCL from an SCL!"); } catch (IllegalArgumentException e) { @@ -821,6 +881,76 @@ public void testAddServletFromServlet() throws Exception fail(e); } } + + @Test + public void testCreateMethodsFromSCI() throws Exception + { + //A filter can be created by an SCI + ContextHandlerCollection contexts = new ContextHandlerCollection(); + _server.setHandler(contexts); + + ServletContextHandler root = new ServletContextHandler(contexts, "/"); + class FilterCreatingSCI implements ServletContainerInitializer + { + @Override + public void onStartup(Set> c, ServletContext ctx) throws ServletException + { + try + { + ctx.createFilter(MyFilter.class); + } + catch (Exception e) + { + fail(e); + } + + try + { + ctx.createServlet(HelloServlet.class); + } + catch (Exception e) + { + fail(e); + } + + try + { + ctx.createListener(MyContextListener.class); + } + catch (Exception e) + { + fail(e); + } + } + } + + root.addBean(new MySCIStarter(root.getServletContext(), new FilterCreatingSCI()), true); + _server.start(); + } + + @Test + public void testCreateMethodsFromSCL() throws Exception + { + //A filter can be created by an SCI + ContextHandlerCollection contexts = new ContextHandlerCollection(); + _server.setHandler(contexts); + + ServletContextHandler root = new ServletContextHandler(contexts, "/"); + class ListenerCreatingSCI implements ServletContainerInitializer + { + @Override + public void onStartup(Set> c, ServletContext ctx) throws ServletException + { + ctx.addListener(new CreatingSCL()); + } + } + + root.addBean(new MySCIStarter(root.getServletContext(), new ListenerCreatingSCI()), true); + _server.start(); + assertTrue((Boolean)root.getServletContext().getAttribute("CreatingSCL.filter")); + assertTrue((Boolean)root.getServletContext().getAttribute("CreatingSCL.servlet")); + assertTrue((Boolean)root.getServletContext().getAttribute("CreatingSCL.listener")); + } @Test public void testAddFilterFromServlet() throws Exception