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

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 6c520e58 fix: guard dashboard provider against null NameServer 
topology (#1042)
6c520e58 is described below

commit 6c520e585251bd142d4fb03d5224ab704a289ce4
Author: 0 <[email protected]>
AuthorDate: Thu Aug 6 14:05:15 2026 +0800

    fix: guard dashboard provider against null NameServer topology (#1042)
    
    examineBrokerClusterInfo payloads can omit the cluster/broker tables or a
    broker can be registered without an address table. The provider dereferenced
    them directly, so one NPE fell into the outer catch and zeroed every 
dashboard
    stat (clusters, brokers, topics, TPS). Treat missing tables as empty and 
skip
    brokers without an address table, matching the defense used by
    RealClusterProvider and RocketMQClusterProvider.
---
 .../studio/rocketmq/RocketMQDashboardProvider.java | 20 +++++++++--
 .../rocketmq/RocketMQDashboardProviderTest.java    | 41 ++++++++++++++++++++++
 2 files changed, 58 insertions(+), 3 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java
 
b/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java
index 320e7422..61bd5dec 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java
@@ -77,8 +77,19 @@ public class RocketMQDashboardProvider implements 
DashboardProvider {
 
         try {
             ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
-            Map<String, Set<String>> clusterAddrTable = 
clusterInfo.getClusterAddrTable();
-            Map<String, BrokerData> brokerAddrTable = 
clusterInfo.getBrokerAddrTable();
+            if (clusterInfo == null) {
+                log.warn("NameServer returned no cluster topology, returning 
empty dashboard");
+                return emptyDashboard();
+            }
+            // The NameServer topology is decoded from JSON; a payload missing 
either
+            // table yields null here. Treat it as empty so a partial topology 
degrades
+            // instead of throwing and zeroing the whole dashboard.
+            Map<String, Set<String>> clusterAddrTable =
+                    clusterInfo.getClusterAddrTable() == null
+                            ? Map.of() : clusterInfo.getClusterAddrTable();
+            Map<String, BrokerData> brokerAddrTable =
+                    clusterInfo.getBrokerAddrTable() == null
+                            ? Map.of() : clusterInfo.getBrokerAddrTable();
 
             totalClusters = clusterAddrTable.size();
             totalBrokers = brokerAddrTable.size();
@@ -86,6 +97,9 @@ public class RocketMQDashboardProvider implements 
DashboardProvider {
             // Collect all unique broker addresses (master only, brokerId=0)
             Set<String> masterAddrs = new HashSet<>();
             for (BrokerData brokerData : brokerAddrTable.values()) {
+                if (brokerData == null || brokerData.getBrokerAddrs() == null) 
{
+                    continue;
+                }
                 String masterAddr = brokerData.getBrokerAddrs().get(0L);
                 if (masterAddr != null) {
                     masterAddrs.add(masterAddr);
@@ -154,7 +168,7 @@ public class RocketMQDashboardProvider implements 
DashboardProvider {
 
                 for (String brokerName : brokerNames) {
                     BrokerData brokerData = brokerAddrTable.get(brokerName);
-                    if (brokerData != null) {
+                    if (brokerData != null && brokerData.getBrokerAddrs() != 
null) {
                         clusterBrokers++;
                         String masterAddr = 
brokerData.getBrokerAddrs().get(0L);
                         if (masterAddr != null) {
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProviderTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProviderTest.java
index c24b55a9..d7707759 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProviderTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProviderTest.java
@@ -48,6 +48,47 @@ class RocketMQDashboardProviderTest {
         
assertThat(dashboard.getClusters().get(0).getVersion()).isEqualTo("V5_3_3");
     }
 
+    @Test
+    void dashboardShouldSurviveNullTopologyTables() throws Exception {
+        DefaultMQAdminExt adminExt = mock(DefaultMQAdminExt.class);
+        ClusterInfo bare = new ClusterInfo();
+        bare.setBrokerAddrTable(null);
+        bare.setClusterAddrTable(null);
+        when(adminExt.examineBrokerClusterInfo()).thenReturn(bare);
+        when(adminExt.fetchAllTopicList()).thenReturn(topicList());
+
+        RocketMQDashboardProvider provider = new 
RocketMQDashboardProvider(adminExt);
+
+        DashboardDataVO dashboard = provider.getDashboardData();
+
+        // A partial NameServer payload must not throw and zero the page.
+        assertThat(dashboard.getStats()).isNotNull();
+        assertThat(dashboard.getClusters()).isEmpty();
+    }
+
+    @Test
+    void dashboardShouldSkipBrokerWithoutAddressTable() throws Exception {
+        DefaultMQAdminExt adminExt = mock(DefaultMQAdminExt.class);
+        ClusterInfo info = new ClusterInfo();
+        HashMap<String, BrokerData> brokerAddrTable = new HashMap<>();
+        brokerAddrTable.put("broker-no-addr", new BrokerData("DefaultCluster", 
"broker-no-addr", null));
+        info.setBrokerAddrTable(brokerAddrTable);
+        HashMap<String, Set<String>> clusterAddrTable = new HashMap<>();
+        clusterAddrTable.put("DefaultCluster", Set.of("broker-no-addr"));
+        info.setClusterAddrTable(clusterAddrTable);
+        when(adminExt.examineBrokerClusterInfo()).thenReturn(info);
+        when(adminExt.fetchAllTopicList()).thenReturn(topicList());
+
+        RocketMQDashboardProvider provider = new 
RocketMQDashboardProvider(adminExt);
+
+        DashboardDataVO dashboard = provider.getDashboardData();
+
+        // A broker without an address table is skipped instead of throwing.
+        assertThat(dashboard.getStats()).isNotNull();
+        assertThat(dashboard.getClusters()).hasSize(1);
+        assertThat(dashboard.getClusters().get(0).getBrokers()).isZero();
+    }
+
     private ClusterInfo clusterInfo() {
         ClusterInfo info = new ClusterInfo();
         HashMap<Long, String> addrs = new HashMap<>();

Reply via email to