This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 039f7c67341777f76fe9cf7168a48d8dc2c5f141
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 9e5a5bcf12..af17824355 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;
@@ -585,8 +586,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
      */
@@ -602,10 +603,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;
         }
@@ -855,7 +873,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]

Reply via email to