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 be7b6c290261..04141df05961 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 @@ -2717,7 +2717,6 @@ public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, @Override public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { - // TODO new in 4.0 LOG.warn(UNIMPLEMENTED_USE_SERVLET_CONTEXT_HANDLER, "addJspFile(String, String)"); return null; } 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 52859a3ed73b..b2b5fa7f3be8 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 @@ -39,6 +39,7 @@ import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; +import javax.servlet.ServletRegistration.Dynamic; import javax.servlet.ServletSecurityElement; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; @@ -1256,6 +1257,33 @@ public ServletRegistration.Dynamic addServlet(String servletName, Servlet servle else return null; //existing completed registration for servlet name } + + @Override + public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) + { + checkDynamic(servletName); + + final ServletHandler handler = ServletContextHandler.this.getServletHandler(); + ServletHolder holder = handler.getServlet(servletName); + if (holder == null) + { + //new servlet + holder = handler.newServletHolder(Source.JAVAX_API); + holder.setName(servletName); + holder.setForcedPath(jspFile); + handler.addServlet(holder); + return dynamicHolderAdded(holder); + } + + //complete a partial registration + if (holder.getClassName() == null && holder.getHeldClass() == null && holder.getForcedPath() == null) + { + holder.setForcedPath(jspFile); + return holder.getRegistration(); + } + else + return null; //existing completed registration for servlet name + } @Override public boolean setInitParameter(String name, String value) 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 276239b93d83..e86dc9aad1d5 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 @@ -59,6 +59,7 @@ import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; +import org.eclipse.jetty.http.pathmap.MappedResource; import org.eclipse.jetty.security.ConstraintSecurityHandler; import org.eclipse.jetty.security.RoleInfo; import org.eclipse.jetty.security.SecurityHandler; @@ -884,6 +885,117 @@ public void onStartup(Set> c, ServletContext ctx) throws ServletExcepti assertThat("Response", response, containsString("Hello World")); } + @Test + public void testAddJspFile() throws Exception + { + ContextHandlerCollection contexts = new ContextHandlerCollection(); + _server.setHandler(contexts); + + ServletContextHandler root = new ServletContextHandler(contexts, "/"); + ServletHolder jspServlet = new ServletHolder(); + jspServlet.setName("jsp"); + jspServlet.setHeldClass(FakeJspServlet.class); + root.addServlet(jspServlet, "*.jsp"); + class JSPAddingSCI implements ServletContainerInitializer + { + @Override + public void onStartup(Set> c, ServletContext ctx) throws ServletException + { + try + { + ServletRegistration rego = ctx.addJspFile("some.jsp", "/path/to/some.jsp"); + rego.addMapping("/somejsp/*"); + } + catch (Exception e) + { + fail(e); + } + } + } + + root.addBean(new MySCIStarter(root.getServletContext(), new JSPAddingSCI()), true); + _server.start(); + MappedResource mappedServlet = root.getServletHandler().getMappedServlet("/somejsp/xxx"); + assertNotNull(mappedServlet.getResource()); + assertEquals("some.jsp", mappedServlet.getResource().getName()); + } + + @Test + public void testAddJspFileWithExistingRegistration() throws Exception + { + ContextHandlerCollection contexts = new ContextHandlerCollection(); + _server.setHandler(contexts); + + ServletContextHandler root = new ServletContextHandler(contexts, "/"); + ServletHolder jspServlet = new ServletHolder(); + jspServlet.setName("jsp"); + jspServlet.setHeldClass(FakeJspServlet.class); + root.addServlet(jspServlet, "*.jsp"); + //add a full registration so that the addJspFile will fail + ServletHolder barServlet = new ServletHolder(); + barServlet.setName("some.jsp"); + barServlet.setHeldClass(HelloServlet.class); + root.addServlet(barServlet, "/bar/*"); + class JSPAddingSCI implements ServletContainerInitializer + { + @Override + public void onStartup(Set> c, ServletContext ctx) throws ServletException + { + try + { + ServletRegistration rego = ctx.addJspFile("some.jsp", "/path/to/some.jsp"); + assertNull(rego); + } + catch (Exception e) + { + fail(e); + } + } + } + + root.addBean(new MySCIStarter(root.getServletContext(), new JSPAddingSCI()), true); + _server.start(); + } + + @Test + public void testAddJspFileWithPartialRegistration() throws Exception + { + ContextHandlerCollection contexts = new ContextHandlerCollection(); + _server.setHandler(contexts); + + ServletContextHandler root = new ServletContextHandler(contexts, "/"); + ServletHolder jspServlet = new ServletHolder(); + jspServlet.setName("jsp"); + jspServlet.setHeldClass(FakeJspServlet.class); + root.addServlet(jspServlet, "*.jsp"); + //add a preliminary registration so that the addJspFile will complete it + ServletHolder barServlet = new ServletHolder(); + barServlet.setName("some.jsp"); + root.addServlet(barServlet, "/bar/*"); + class JSPAddingSCI implements ServletContainerInitializer + { + @Override + public void onStartup(Set> c, ServletContext ctx) throws ServletException + { + try + { + ServletRegistration rego = ctx.addJspFile("some.jsp", "/path/to/some.jsp"); + assertNotNull(rego); + } + catch (Exception e) + { + fail(e); + } + } + } + + root.addBean(new MySCIStarter(root.getServletContext(), new JSPAddingSCI()), true); + _server.start(); + MappedResource mappedServlet = root.getServletHandler().getMappedServlet("/bar/xxx"); + assertNotNull(mappedServlet.getResource()); + assertEquals("some.jsp", mappedServlet.getResource().getName()); + } + @Test public void testAddServletAfterStart() throws Exception { @@ -1391,6 +1503,11 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se } } } + + public static class FakeJspServlet extends HttpServlet + { + + } public static class ServletAddingServlet extends HttpServlet { diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java index ceed5da88795..9ac95f1c9dd2 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DemoBaseTests.java @@ -139,10 +139,21 @@ public void testSpec() throws Exception assertTrue(run1.awaitConsoleLogsFor("Started Server@", 20, TimeUnit.SECONDS)); startHttpClient(); + + //test the async listener ContentResponse response = client.POST("http://localhost:" + httpPort + "/test-spec/asy/xx").send(); assertEquals(HttpStatus.OK_200, response.getStatus()); assertThat(response.getContentAsString(), containsString("PASS")); assertThat(response.getContentAsString(), not(containsString("FAIL"))); + + //test the servlet 3.1/4 features + response = client.POST("http://localhost:" + httpPort + "/test-spec/test/xx").send(); + assertThat(response.getContentAsString(), containsString("PASS")); + assertThat(response.getContentAsString(), not(containsString("FAIL"))); + + //test dynamic jsp + response = client.POST("http://localhost:" + httpPort + "/test-spec/dynamicjsp/xx").send(); + assertThat(response.getContentAsString(), containsString("Programmatically Added Jsp File")); } } diff --git a/tests/test-webapps/test-servlet-spec/test-container-initializer/src/main/java/com/acme/initializer/FooInitializer.java b/tests/test-webapps/test-servlet-spec/test-container-initializer/src/main/java/com/acme/initializer/FooInitializer.java index 9c5d1cf523b2..5f19fba76686 100644 --- a/tests/test-webapps/test-servlet-spec/test-container-initializer/src/main/java/com/acme/initializer/FooInitializer.java +++ b/tests/test-webapps/test-servlet-spec/test-container-initializer/src/main/java/com/acme/initializer/FooInitializer.java @@ -103,5 +103,10 @@ public void onStartup(Set> classes, ServletContext context) ServletRegistration.Dynamic reg = context.addServlet("AnnotationTest", "com.acme.AnnotationTest"); context.setAttribute("com.acme.AnnotationTest.complete", (reg == null)); context.addListener(new FooListener()); + + //test adding jsp file dynamically + ServletRegistration.Dynamic jspFile = context.addJspFile("dynamic.jsp", "/dynamic.jsp"); + context.setAttribute("com.acme.jsp.file", (jspFile != null)); + jspFile.addMapping("/dynamicjsp/*"); } } 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 a252edf73006..f58c71a6a416 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 @@ -262,7 +262,11 @@ else if (!classNames.containsAll(__HandlesTypes)) out.println("

ServletContextListener Registration Prevented from ServletContextListener

"); Boolean webListenerPrevention = (Boolean)config.getServletContext().getAttribute("com.acme.AnnotationTest.sclFromSclRegoTest"); out.println("

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

"); - + + out.println("

Add Jsp File Registration

"); + complete = (Boolean)config.getServletContext().getAttribute("com.acme.jsp.file"); + out.println("

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

"); + out.println("

ServletContextListener In web.xml Injected

"); Boolean listenerInject = (Boolean)config.getServletContext().getAttribute("com.acme.AnnotationTest.sclInjectTest"); out.println("

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

"); diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/dynamic.jsp b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/dynamic.jsp new file mode 100644 index 000000000000..a42f8c3779a3 --- /dev/null +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/dynamic.jsp @@ -0,0 +1,16 @@ +<%@ page contentType="text/html; charset=UTF-8" %> +<%@ page import="java.util.*"%> +<%@ page import="javax.servlet.*" %> +<%@ page import="javax.servlet.http.*" %> + + +Dynamic + + + + +

Programmatically Added Jsp File

+ Success. + + + diff --git a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html index 1c0323af8939..921c562720f9 100644 --- a/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html +++ b/tests/test-webapps/test-servlet-spec/test-spec-webapp/src/main/webapp/index.html @@ -30,6 +30,10 @@

Test Defaults, Annotations, Fragments and Initializers

+

Test Dynamically Added Jsp File

+

Click the link to test accessing a programmatically added jsp file

+Dynamically added jsp +

Test Static Content from Fragment

Click the link to test accessing static content from a fragment's META-INF/resources

Static resource from a fragment