Author: kkolinko Date: Mon Jul 14 23:57:35 2014 New Revision: 1610562 URL: http://svn.apache.org/r1610562 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56717 Fix duplicate registration of MapperListener during repeated starts of embedded Tomcat. Properly unregister it when Tomcat stops.
Added: tomcat/trunk/test/org/apache/catalina/mapper/TestMapperListener.java (with props) Modified: tomcat/trunk/java/org/apache/catalina/mapper/MapperListener.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/mapper/MapperListener.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/mapper/MapperListener.java?rev=1610562&r1=1610561&r2=1610562&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/mapper/MapperListener.java (original) +++ tomcat/trunk/java/org/apache/catalina/mapper/MapperListener.java Mon Jul 14 23:57:35 2014 @@ -116,6 +116,9 @@ public class MapperListener extends Life @Override public void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); + + Engine engine = (Engine) service.getContainer(); + removeListeners(engine); } Added: tomcat/trunk/test/org/apache/catalina/mapper/TestMapperListener.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/mapper/TestMapperListener.java?rev=1610562&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/catalina/mapper/TestMapperListener.java (added) +++ tomcat/trunk/test/org/apache/catalina/mapper/TestMapperListener.java Mon Jul 14 23:57:35 2014 @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.mapper; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Container; +import org.apache.catalina.ContainerListener; +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.websocket.server.WsContextListener; + +public class TestMapperListener extends TomcatBaseTest { + + @Test + public void testTomcatRestartListenerCount_Bug56717() throws IOException, + LifecycleException { + // The test runs Tomcat twice, tests that it has started successfully, + // and compares the counts of listeners registered on containers + // after the first and the second starts. + // Sample request is from TestTomcat#testSingleWebapp() + + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File(getBuildDirectory(), "webapps/examples"); + // app dir is relative to server home + Context ctxt = tomcat.addWebapp(null, "/examples", + appDir.getAbsolutePath()); + ctxt.addApplicationListener(WsContextListener.class.getName()); + tomcat.start(); + + ByteChunk res; + String text; + res = getUrl("http://localhost:" + getPort() + + "/examples/servlets/servlet/HelloWorldExample"); + text = res.toString(); + Assert.assertTrue(text, text.contains("<h1>Hello World!</h1>")); + + List<ListenersInfo> listenersFirst = new ArrayList<>(); + populateListenersInfo(listenersFirst, tomcat.getEngine()); + + tomcat.stop(); + tomcat.start(); + + res = getUrl("http://localhost:" + getPort() + + "/examples/servlets/servlet/HelloWorldExample"); + text = res.toString(); + Assert.assertTrue(text, text.contains("<h1>Hello World!</h1>")); + + List<ListenersInfo> listenersSecond = new ArrayList<>(); + populateListenersInfo(listenersSecond, tomcat.getEngine()); + + Assert.assertEquals(listenersFirst.size(), listenersSecond.size()); + for (int i = 0, len = listenersFirst.size(); i < len; i++) { + ListenersInfo a = listenersFirst.get(i); + ListenersInfo b = listenersSecond.get(i); + boolean equal = a.container.getClass() == b.container.getClass() + && a.containerListeners.length == b.containerListeners.length + && a.lifecycleListeners.length == b.lifecycleListeners.length; + if (!equal) { + Assert.fail("The lists of listeners differ:\n" + a + "\n" + b); + } + } + } + + private static class ListenersInfo { + public final Container container; + public final ContainerListener[] containerListeners; + public final LifecycleListener[] lifecycleListeners; + + public ListenersInfo(Container container, + ContainerListener[] containerListeners, + LifecycleListener[] lifecycleListeners) { + this.container = container; + this.containerListeners = containerListeners; + this.lifecycleListeners = lifecycleListeners; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("[container: \"").append(container) + .append("\"\n containerListeners.length: ") + .append(containerListeners.length) + .append(", lifecycleListeners.length: ") + .append(lifecycleListeners.length) + .append("\n containerListeners: ") + .append(Arrays.asList(containerListeners)) + .append("\n lifecycleListeners: ") + .append(Arrays.asList(lifecycleListeners)).append("\n]"); + return buf.toString(); + } + } + + private static void populateListenersInfo(List<ListenersInfo> list, + Container container) { + list.add(new ListenersInfo(container, container + .findContainerListeners(), container.findLifecycleListeners())); + for (Container child : container.findChildren()) { + populateListenersInfo(list, child); + } + } +} Propchange: tomcat/trunk/test/org/apache/catalina/mapper/TestMapperListener.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1610562&r1=1610561&r2=1610562&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Mon Jul 14 23:57:35 2014 @@ -59,6 +59,11 @@ <bug>56712</bug>: Fix session idle time calculations in <code>PersistenceManager</code>. (kkolinko) </fix> + <fix> + <bug>56717</bug>: Fix duplicate registration of + <code>MapperListener</code> during repeated starts of embedded Tomcat. + (kkolinko) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org