Author: markt Date: Tue Oct 26 22:09:20 2010 New Revision: 1027760 URL: http://svn.apache.org/viewvc?rev=1027760&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50157 Ensure MapperListener is only added to a container object once. Also - Improve debug logging for MapperListener registration. - Expose names of LifecycleListeners and ContainerListers for StandardContext via JMX.
Modified: tomcat/trunk/java/org/apache/catalina/connector/LocalStrings.properties tomcat/trunk/java/org/apache/catalina/connector/MapperListener.java tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml tomcat/trunk/java/org/apache/catalina/mbeans/ContainerMBean.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/connector/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/LocalStrings.properties?rev=1027760&r1=1027759&r2=1027760&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/connector/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/catalina/connector/LocalStrings.properties Tue Oct 26 22:09:20 2010 @@ -73,12 +73,13 @@ cometEvent.nullRequest=The event object # # MapperListener # -mapperListener.unknownDefaultHost=Unknown default host: {0} -mapperListener.registerHost=Register host {0} at domain {1} -mapperListener.unregisterHost=Unregister host {0} at domain {1} -mapperListener.registerContext=Register Context {0} -mapperListener.unregisterContext=Unregister Context {0} -mapperListener.registerWrapper=Register Wrapper {0} in Context {1} +mapperListener.unknownDefaultHost=Unknown default host [{0}] for connector [{1}] +mapperListener.registerHost=Register host [{0}] at domain [{1}] for connector [{2}] +mapperListener.unregisterHost=Unregister host [{0}] at domain [{1}] for connector [{2}] +mapperListener.registerContext=Register Context [{0}] for connector [{1}] +mapperListener.unregisterContext=Unregister Context [{0}] for connector [{1}] +mapperListener.registerWrapper=Register Wrapper [{0}] in Context [{1}] for connector [{2}] +mapperListener.unregisterWrapper=Unregister Wrapper [{0}] in Context [{1}] for connector [{2}] mapperListener.addMBeanListenerFail=Failed to add MBean notification listener for connector [{0}] in domain [{1}]. Adding Hosts, Contexts and Wrappers will not be visible to the connector. mapperListener.removeMBeanListenerFail=Failed to remove MBean notification listener for connector [{0}] in domain [{1}]. This may result in a memory leak. mapperListener.lifecycleListenerFail=Failed to add Lifecycle listener to object [{0}]. Changes in the object state may not be correctly reflected in the mapper for connector [{1}] in domain [{2}]. Modified: tomcat/trunk/java/org/apache/catalina/connector/MapperListener.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/MapperListener.java?rev=1027760&r1=1027759&r2=1027760&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/connector/MapperListener.java (original) +++ tomcat/trunk/java/org/apache/catalina/connector/MapperListener.java Tue Oct 26 22:09:20 2010 @@ -101,13 +101,12 @@ public class MapperListener implements C findDefaultHost(); Engine engine = (Engine) connector.getService().getContainer(); - engine.addContainerListener(this); + addListeners(engine); Container[] conHosts = engine.findChildren(); for (Container conHost : conHosts) { Host host = (Host) conHost; if (!LifecycleState.NEW.equals(host.getState())) { - host.addLifecycleListener(this); // Registering the host will register the context and wrappers registerHost(host); } @@ -125,29 +124,28 @@ public class MapperListener implements C // --------------------------------------------- Container Listener methods + @Override public void containerEvent(ContainerEvent event) { if (event.getType() == Container.ADD_CHILD_EVENT) { Container child = (Container) event.getData(); - child.addLifecycleListener(this); - child.addContainerListener(this); - if (child instanceof Host) { - registerHost((Host) child); - } else if (child instanceof Context) { - registerContext((Context) child); - } else if (child instanceof Wrapper) { - registerWrapper((Wrapper) child); + addListeners(child); + // If child is started then it is too late for life-cycle listener + // to register the child so register it here + if (child.getState().isAvailable()) { + if (child instanceof Host) { + registerHost((Host) child); + } else if (child instanceof Context) { + registerContext((Context) child); + } else if (child instanceof Wrapper) { + registerWrapper((Wrapper) child); + } } } else if (event.getType() == Container.REMOVE_CHILD_EVENT) { Container child = (Container) event.getData(); removeListeners(child); - if (child instanceof Host) { - unregisterHost((Host) child); - } else if (child instanceof Context) { - unregisterContext((Context) child); - } else if (child instanceof Wrapper) { - unregisterWrapper((Wrapper) child); - } + // No need to unregister - life-cycle listener will handle this when + // the child stops } else if (event.getType() == Host.ADD_ALIAS_EVENT) { // Handle dynamically adding host aliases mapper.addHostAlias(((Host) event.getSource()).getName(), @@ -260,7 +258,7 @@ public class MapperListener implements C mapper.setDefaultHostName(defaultHost); } else { log.warn(sm.getString("mapperListener.unknownDefaultHost", - defaultHost)); + defaultHost, connector)); } } @@ -273,14 +271,12 @@ public class MapperListener implements C String[] aliases = host.findAliases(); mapper.addHost(host.getName(), aliases, host); - host.addContainerListener(this); - for (Container container : host.findChildren()) { registerContext((Context) container); } if(log.isDebugEnabled()) { - log.debug(sm.getString - ("mapperListener.registerHost", host.getName(), domain)); + log.debug(sm.getString("mapperListener.registerHost", + host.getName(), domain, connector)); } } @@ -296,7 +292,7 @@ public class MapperListener implements C if(log.isDebugEnabled()) log.debug(sm.getString("mapperListener.unregisterHost", hostname, - domain)); + domain, connector)); } @@ -306,6 +302,8 @@ public class MapperListener implements C private void unregisterWrapper(Wrapper wrapper) { String contextName = wrapper.getParent().getName(); + String wrapperName = wrapper.getName(); + if ("/".equals(contextName)) { contextName = ""; } @@ -316,6 +314,11 @@ public class MapperListener implements C for (String mapping : mappings) { mapper.removeWrapper(hostName, contextName, mapping); } + + if(log.isDebugEnabled()) { + log.debug(sm.getString("mapperListener.unregisterWrapper", + wrapperName, contextName, connector)); + } } @@ -336,15 +339,13 @@ public class MapperListener implements C mapper.addContext(host.getName(), host, contextName, context, welcomeFiles, resources); - context.addContainerListener(this); - for (Container container : context.findChildren()) { registerWrapper((Wrapper) container); } if(log.isDebugEnabled()) { - log.debug(sm.getString - ("mapperListener.registerContext", contextName)); + log.debug(sm.getString("mapperListener.registerContext", + contextName, connector)); } } @@ -366,8 +367,8 @@ public class MapperListener implements C String hostName = context.getParent().getName(); if(log.isDebugEnabled()) - log.debug(sm.getString - ("mapperListener.unregisterContext", contextName)); + log.debug(sm.getString("mapperListener.unregisterContext", + contextName, connector)); mapper.removeContext(hostName, contextName); } @@ -394,11 +395,9 @@ public class MapperListener implements C jspWildCard); } - wrapper.addContainerListener(this); - if(log.isDebugEnabled()) { log.debug(sm.getString("mapperListener.registerWrapper", - wrapperName, contextName)); + wrapperName, contextName, connector)); } } @@ -425,6 +424,21 @@ public class MapperListener implements C } } + + /** + * Add this mapper to the container and all child containers + * + * @param container + */ + private void addListeners(Container container) { + container.addContainerListener(this); + container.addLifecycleListener(this); + for (Container child : container.findChildren()) { + addListeners(child); + } + } + + /** * Remove this mapper from the container and all child containers * Modified: tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml?rev=1027760&r1=1027759&r2=1027760&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml (original) +++ tomcat/trunk/java/org/apache/catalina/core/mbeans-descriptors.xml Tue Oct 26 22:09:20 2010 @@ -583,6 +583,12 @@ returnType="java.lang.String"> </operation> + <operation name="findContainerListenerNames" + description="Return the set of container listener class names configured for this application." + impact="INFO" + returnType="[Ljava.lang.String;"> + </operation> + <operation name="findErrorPage" description="Return the error page entry for the specified HTTP error code, if any; otherwise return null" impact="ACTION" @@ -634,6 +640,12 @@ returnType="[Ljava.lang.String;"> </operation> + <operation name="findLifecycleListenerNames" + description="Return the set of lifecycle listener class names configured for this application." + impact="INFO" + returnType="[Ljava.lang.String;"> + </operation> + <operation name="findMimeMapping" description="Return the MIME type to which the specified extension is mapped, if any; otherwise return null." impact="ACTION" Modified: tomcat/trunk/java/org/apache/catalina/mbeans/ContainerMBean.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/mbeans/ContainerMBean.java?rev=1027760&r1=1027759&r2=1027760&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/mbeans/ContainerMBean.java (original) +++ tomcat/trunk/java/org/apache/catalina/mbeans/ContainerMBean.java Tue Oct 26 22:09:20 2010 @@ -17,6 +17,9 @@ package org.apache.catalina.mbeans; +import java.util.ArrayList; +import java.util.List; + import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; @@ -25,6 +28,7 @@ import javax.management.RuntimeOperation import javax.management.modelmbean.InvalidTargetObjectTypeException; import org.apache.catalina.Container; +import org.apache.catalina.ContainerListener; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; import org.apache.catalina.Valve; @@ -265,4 +269,57 @@ public class ContainerMBean extends Base } } + + /** + * List the class name of each of the lifecycle listeners added to this + * container. + */ + public String[] findLifecycleListenerNames() throws MBeanException { + ContainerBase container = null; + List<String> result = new ArrayList<String>(); + + try { + container = (ContainerBase) getManagedResource(); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (RuntimeOperationsException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + LifecycleListener[] listeners = container.findLifecycleListeners(); + for(LifecycleListener listener: listeners){ + result.add(listener.getClass().getName()); + } + + return result.toArray(new String[result.size()]); + } + + + /** + * List the class name of each of the container listeners added to this + * container. + */ + public String[] findContainerListenerNames() throws MBeanException { + ContainerBase container = null; + List<String> result = new ArrayList<String>(); + + try { + container = (ContainerBase) getManagedResource(); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (RuntimeOperationsException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + ContainerListener[] listeners = container.findContainerListeners(); + for(ContainerListener listener: listeners){ + result.add(listener.getClass().getName()); + } + + return result.toArray(new String[result.size()]); + } } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1027760&r1=1027759&r2=1027760&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Oct 26 22:09:20 2010 @@ -57,6 +57,17 @@ <bug>50138</bug>: Fix threading issues in <code>org.apache.catalina.security.SecurityUtil</code>. (markt) </fix> + <fix> + <bug>50157</bug>: Ensure MapperListener is only added to a container + object once. (markt) + </fix> + <add> + Improve debug logging for MapperListener registration. (markt) + </add> + <add> + Expose names of LifecycleListeners and ContainerListers for + StandardContext via JMX. (markt) + </add> </changelog> </subsection> <subsection name="Jasper"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org