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<>();