diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEmbedder.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEmbedder.java index 316c2a9ed6f7..3b909d8b9f9a 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEmbedder.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyEmbedder.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ShutdownMonitor; import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.resource.Resource; @@ -227,6 +228,12 @@ protected void redeployWebApp() throws Exception { if (!webApp.isStopped()) webApp.stop(); + + //clear the ServletHandler, which may have + //remembered "durable" Servlets, Filters, Listeners + //from the context xml file, but as we will re-apply + //the context xml, we should not retain them + webApp.setServletHandler(new ServletHandler()); //regenerate config properties applyWebAppProperties(); diff --git a/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/SomeListener.java b/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/SomeListener.java new file mode 100644 index 000000000000..981dce1b2047 --- /dev/null +++ b/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/SomeListener.java @@ -0,0 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.maven.plugin; + +import java.util.EventListener; + +public class SomeListener implements EventListener +{ + +} diff --git a/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/TestJettyEmbedder.java b/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/TestJettyEmbedder.java index 489f458a114d..48859c77b6cc 100644 --- a/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/TestJettyEmbedder.java +++ b/jetty-maven-plugin/src/test/java/org/eclipse/jetty/maven/plugin/TestJettyEmbedder.java @@ -21,6 +21,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.servlet.ListenerHolder; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; @@ -29,9 +30,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; @ExtendWith(WorkDirExtension.class) public class TestJettyEmbedder @@ -117,6 +121,37 @@ public void testJettyEmbedder() assertNotNull(contexts); assertTrue(contexts.contains(otherHandler)); assertTrue(contexts.contains(webApp)); + + //stop the webapp and check durable listener retained + jetty.getWebApp().stop(); + boolean someListener = false; + for (ListenerHolder h : webApp.getServletHandler().getListeners()) + { + if (h.getHeldClass() != null && "org.eclipse.jetty.maven.plugin.SomeListener".equalsIgnoreCase(h.getHeldClass().getName())) + { + if (someListener) + fail("Duplicate listeners"); + else + someListener = true; + } + } + + + //restart the webapp + jetty.redeployWebApp(); + someListener = false; + + //ensure still only 1 listener + for (ListenerHolder h : webApp.getServletHandler().getListeners()) + { + if (h.getHeldClass() != null && "org.eclipse.jetty.maven.plugin.SomeListener".equalsIgnoreCase(h.getHeldClass().getName())) + { + if (someListener) + fail("Duplicate listeners"); + else + someListener = true; + } + } } finally { diff --git a/jetty-maven-plugin/src/test/resources/embedder-context.xml b/jetty-maven-plugin/src/test/resources/embedder-context.xml index c13affca5e7a..bde6592cc3e4 100644 --- a/jetty-maven-plugin/src/test/resources/embedder-context.xml +++ b/jetty-maven-plugin/src/test/resources/embedder-context.xml @@ -3,4 +3,16 @@ /embedder + + + + + + + + + + + + diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java index 1ee5a049a8ca..e2435398e6cb 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ServletHandlerTest.java @@ -64,6 +64,12 @@ public class ServletHandlerTest FilterHolder fh5 = new FilterHolder(Source.JAVAX_API); FilterMapping fm5 = new FilterMapping(); + FilterHolder fh6 = new FilterHolder(Source.EMBEDDED); + FilterMapping fm6 = new FilterMapping(); + + FilterHolder fh7 = new FilterHolder(Source.EMBEDDED); + FilterMapping fm7 = new FilterMapping(); + ServletHolder sh1 = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, "foo.xml")); ServletMapping sm1 = new ServletMapping(); @@ -73,6 +79,12 @@ public class ServletHandlerTest ServletHolder sh3 = new ServletHolder(new Source(Source.Origin.DESCRIPTOR, "foo.xml")); ServletMapping sm3 = new ServletMapping(); + ServletHolder sh4 = new ServletHolder(Source.EMBEDDED); + ServletMapping sm4 = new ServletMapping(); + + ServletHolder sh5 = new ServletHolder(Source.EMBEDDED); + ServletMapping sm5 = new ServletMapping(); + @BeforeEach public void initMappings() { @@ -842,50 +854,61 @@ public void testDurable() throws Exception ServletContextHandler context = new ServletContextHandler(); server.setHandler(context); ServletHandler handler = new ServletHandler(); + handler.setEnsureDefaultServlet(false); context.setHandler(handler); ListenerHolder lh1 = new ListenerHolder(HSListener.class); ListenerHolder lh2 = new ListenerHolder(SCListener.class); - fh1.setFilter(new SomeFilter()); - fm1.setPathSpec("/sm1"); - fm1.setFilterHolder(fh1); - fh2.setFilter(new SomeFilter(){}); - fm2.setPathSpec("/sm2"); - fm2.setFilterHolder(fh2); - sh1.setServlet(new SomeServlet()); - sm1.setPathSpec("/sm1"); - sm1.setServletName(sh1.getName()); - sh2.setServlet(new SomeServlet()); - sm2.setPathSpec("/sm2"); - sm2.setServletName(sh2.getName()); + fh6.setFilter(new SomeFilter()); + fm6.setPathSpec("/sm4"); + fm6.setFilterHolder(fh6); + fh7.setFilter(new SomeFilter(){}); + fm7.setPathSpec("/sm5"); + fm7.setFilterHolder(fh7); + sh4.setServlet(new SomeServlet()); + sm4.setPathSpec("/sm4"); + sm4.setServletName(sh4.getName()); + sh5.setServlet(new SomeServlet()); + sm5.setPathSpec("/sm5"); + sm5.setServletName(sh5.getName()); handler.setListeners(new ListenerHolder[] {lh1}); - handler.setFilters(new FilterHolder[] {fh1}); - handler.setFilterMappings(new FilterMapping[] {fm1}); - handler.setServlets(new ServletHolder[] {sh1}); - handler.setServletMappings(new ServletMapping[] {sm1}); + handler.setFilters(new FilterHolder[] {fh6}); + handler.setFilterMappings(new FilterMapping[] {fm6}); + handler.setServlets(new ServletHolder[] {sh4}); + handler.setServletMappings(new ServletMapping[] {sm4}); server.start(); + //emulate some listeners, servlets and filters added after the ServletHandler has started, + //these cannot be durable handler.setListeners(new ListenerHolder[] {lh1, lh2}); - handler.setFilters(new FilterHolder[] {fh1, fh2}); - handler.setFilterMappings(new FilterMapping[] {fm1, fm2}); - handler.setServlets(new ServletHolder[] {sh1, sh2}); - handler.setServletMappings(new ServletMapping[] {sm1, sm2}); + handler.setFilters(new FilterHolder[] {fh6, fh7}); + handler.setFilterMappings(new FilterMapping[] {fm6, fm7}); + handler.setServlets(new ServletHolder[] {sh4, sh5}); + handler.setServletMappings(new ServletMapping[] {sm4, sm5}); assertThat(Arrays.asList(handler.getListeners()), contains(lh1, lh2)); - assertThat(Arrays.asList(handler.getFilters()), contains(fh1, fh2)); - assertThat(Arrays.asList(handler.getFilterMappings()), contains(fm1, fm2)); - assertThat(Arrays.asList(handler.getServlets()), contains(sh1, sh2)); - assertThat(Arrays.asList(handler.getServletMappings()), contains(sm1, sm2)); + assertThat(Arrays.asList(handler.getFilters()), contains(fh6, fh7)); + assertThat(Arrays.asList(handler.getFilterMappings()), contains(fm6, fm7)); + assertThat(Arrays.asList(handler.getServlets()), contains(sh4, sh5)); + assertThat(Arrays.asList(handler.getServletMappings()), contains(sm4, sm5)); server.stop(); assertThat(Arrays.asList(handler.getListeners()), contains(lh1)); - assertThat(Arrays.asList(handler.getFilters()), contains(fh1)); - assertThat(Arrays.asList(handler.getFilterMappings()), contains(fm1)); - assertThat(Arrays.asList(handler.getServlets()), contains(sh1)); - assertThat(Arrays.asList(handler.getServletMappings()), contains(sm1)); + assertThat(Arrays.asList(handler.getFilters()), contains(fh6)); + assertThat(Arrays.asList(handler.getFilterMappings()), contains(fm6)); + assertThat(Arrays.asList(handler.getServlets()), contains(sh4)); + assertThat(Arrays.asList(handler.getServletMappings()), contains(sm4)); + + server.start(); + + assertThat(handler.getListeners().length, is(1)); + assertThat(handler.getFilters().length, is(1)); + assertThat(handler.getFilterMappings().length, is(1)); + assertThat(handler.getServlets().length, is(1)); + assertThat(handler.getServletMappings().length, is(1)); } public static class HSListener implements HttpSessionListener