This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 710dc56606f36fbcbae0640fb3ddf5f902c10450 Author: opencode <[email protected]> AuthorDate: Wed Oct 7 12:30:11 2026 +0200 Avoid null valve MBean names in ContainerMBean and MBeanFactory Adding a valve to a container that is not running links the valve into the pipeline but does not initialize it, so it has no MBean name. The valve creation operations dereferenced the missing name and threw an uncaught NullPointerException, and the valve was left without a name that removeValve could later match against, which made any subsequent removeValve call fail on that valve as well. When the pipeline was running but starting the new valve failed, the pipeline cleaned the valve up without adding it, yet the creation operations still returned the name of the discarded valve. Only report a name for a valve that was actually added, tolerate valves without a name when comparing, and apply the same handling to the equivalent operations of the valve factory. --- .../org/apache/catalina/mbeans/ContainerMBean.java | 28 ++++++++++++++++++--- java/org/apache/catalina/mbeans/MBeanFactory.java | 29 ++++++++++++++++++---- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/java/org/apache/catalina/mbeans/ContainerMBean.java b/java/org/apache/catalina/mbeans/ContainerMBean.java index d64b4b9f64..3466bb0a7e 100644 --- a/java/org/apache/catalina/mbeans/ContainerMBean.java +++ b/java/org/apache/catalina/mbeans/ContainerMBean.java @@ -28,6 +28,7 @@ import org.apache.catalina.ContainerListener; import org.apache.catalina.JmxEnabled; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Pipeline; import org.apache.catalina.Valve; import org.apache.catalina.core.ContainerBase; import org.apache.catalina.core.StandardContext; @@ -114,7 +115,8 @@ public class ContainerMBean extends BaseCatalinaMBean<ContainerBase> { * * @param valveType ClassName of the valve to be added * - * @return the MBean name of the new valve + * @return the MBean name of the new valve, or null if the valve was not + * added or has no registered MBean * * @throws MBeanException if adding the valve failed */ @@ -122,10 +124,27 @@ public class ContainerMBean extends BaseCatalinaMBean<ContainerBase> { Valve valve = (Valve) newInstance(valveType); Container container = doGetManagedResource(); - container.getPipeline().addValve(valve); + Pipeline pipeline = container.getPipeline(); + pipeline.addValve(valve); + + // If the pipeline is running and starting the valve fails, the valve + // is cleaned up and not added. The pipeline logs the failure. + boolean added = false; + for (Valve pipelineValve : pipeline.getValves()) { + if (pipelineValve == valve) { + added = true; + break; + } + } + if (!added) { + return null; + } if (valve instanceof JmxEnabled) { - return ((JmxEnabled) valve).getObjectName().toString(); + // A container that is not running does not initialize the valve, + // so no MBean name is available + ObjectName oname = ((JmxEnabled) valve).getObjectName(); + return oname == null ? null : oname.toString(); } else { return null; } @@ -154,7 +173,8 @@ public class ContainerMBean extends BaseCatalinaMBean<ContainerBase> { for (Valve valve : valves) { if (valve instanceof JmxEnabled) { ObjectName voname = ((JmxEnabled) valve).getObjectName(); - if (voname.equals(oname)) { + // A valve that has not been initialized has no name + if (oname.equals(voname)) { container.getPipeline().removeValve(valve); } } diff --git a/java/org/apache/catalina/mbeans/MBeanFactory.java b/java/org/apache/catalina/mbeans/MBeanFactory.java index 7f181383e8..81f2fb2b09 100644 --- a/java/org/apache/catalina/mbeans/MBeanFactory.java +++ b/java/org/apache/catalina/mbeans/MBeanFactory.java @@ -27,6 +27,7 @@ import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; import org.apache.catalina.JmxEnabled; +import org.apache.catalina.Pipeline; import org.apache.catalina.Realm; import org.apache.catalina.Server; import org.apache.catalina.Service; @@ -616,8 +617,8 @@ public class MBeanFactory { * @param className The fully qualified class name of the {@link Valve} to create * @param parent The MBean name of the associated parent {@link Container}. * - * @return The MBean name of the {@link Valve} that was created or <code>null</code> if the {@link Valve} does not - * implement {@link JmxEnabled}. + * @return The MBean name of the {@link Valve} that was created or <code>null</code> if the {@link Valve} was not + * added, does not implement {@link JmxEnabled} or has no registered MBean. * * @exception Exception if an MBean cannot be created or registered */ @@ -633,10 +634,27 @@ public class MBeanFactory { Valve valve = (Valve) Class.forName(className).getConstructor().newInstance(); - container.getPipeline().addValve(valve); + Pipeline pipeline = container.getPipeline(); + pipeline.addValve(valve); + + // If the pipeline is running and starting the valve fails, the valve + // is cleaned up and not added. The pipeline logs the failure. + boolean added = false; + for (Valve pipelineValve : pipeline.getValves()) { + if (pipelineValve == valve) { + added = true; + break; + } + } + if (!added) { + return null; + } if (valve instanceof JmxEnabled) { - return ((JmxEnabled) valve).getObjectName().toString(); + // A container that is not running does not initialize the valve, + // so no MBean name is available + ObjectName oname = ((JmxEnabled) valve).getObjectName(); + return oname == null ? null : oname.toString(); } else { return null; } @@ -886,7 +904,8 @@ public class MBeanFactory { for (Valve valve : valves) { if (valve instanceof JmxEnabled) { ObjectName voname = ((JmxEnabled) valve).getObjectName(); - if (voname.equals(oname)) { + // A valve that has not been initialized has no name + if (oname.equals(voname)) { container.getPipeline().removeValve(valve); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
