Skip to content

Commit

Permalink
Issue #11039 duplicate durable listeners on maven restart (#11042)
Browse files Browse the repository at this point in the history
  • Loading branch information
janbartel committed Dec 13, 2023
1 parent 90244c3 commit 4df28eb
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 28 deletions.
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down
@@ -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
{

}
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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
{
Expand Down
12 changes: 12 additions & 0 deletions jetty-maven-plugin/src/test/resources/embedder-context.xml
Expand Up @@ -3,4 +3,16 @@

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/embedder</Set>

<Get name="servletHandler">
<Call name="addListener">
<Arg>
<New class="org.eclipse.jetty.servlet.ListenerHolder">
<Set name="listener">
<New class="org.eclipse.jetty.maven.plugin.SomeListener"/>
</Set>
</New>
</Arg>
</Call>
</Get>
</Configure>
Expand Up @@ -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();

Expand All @@ -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()
{
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 4df28eb

Please sign in to comment.