From 5dbf47b6c9b105003949ecc7abc0c8e91b30783f Mon Sep 17 00:00:00 2001 From: yyqdbngt <300715189+yyqdbngt@users.noreply.github.com> Date: Fri, 31 Jul 2026 22:16:38 +0800 Subject: [PATCH] fix: guard several edge cases that crash at runtime - TopicServiceImpl: sending a message to a topic without any broker route threw IndexOutOfBoundsException on topicConfigInfos.get(0); throw a ServiceException with a clear message instead - DashboardCollectTask: kvTable.get("getTotalTps") could be null or blank, causing NPE or a divide-by-zero on the empty split result; skip the broker in that case - DashboardCollectServiceImpl: an empty/corrupt dashboard data file makes JSONObject.parse return null and json.entrySet() NPE; return an empty map instead - FileUserStrategy: a non-numeric role in users.properties threw NumberFormatException outside any try/catch and aborted startup; treat it as a normal user (role 0) and log a warning --- .../service/impl/DashboardCollectServiceImpl.java | 7 ++++++- .../rocketmq/dashboard/service/impl/TopicServiceImpl.java | 4 ++++ .../dashboard/service/strategy/FileUserStrategy.java | 7 ++++++- .../rocketmq/dashboard/task/DashboardCollectTask.java | 6 +++++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/rocketmq/dashboard/service/impl/DashboardCollectServiceImpl.java b/src/main/java/org/apache/rocketmq/dashboard/service/impl/DashboardCollectServiceImpl.java index 05006158..3624fa95 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/service/impl/DashboardCollectServiceImpl.java +++ b/src/main/java/org/apache/rocketmq/dashboard/service/impl/DashboardCollectServiceImpl.java @@ -115,7 +115,12 @@ public Map> jsonDataFile2map(File file) { for (String string : strings) { sb.append(string); } - JSONObject json = (JSONObject) JSONObject.parse(sb.toString()); + Object parsed = JSONObject.parse(sb.toString()); + if (parsed == null) { + log.warn("No valid dashboard data in file: {}", file.getAbsolutePath()); + return Maps.newHashMap(); + } + JSONObject json = (JSONObject) parsed; Set> entries = json.entrySet(); Map> map = Maps.newHashMap(); for (Map.Entry entry : entries) { diff --git a/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java b/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java index e1e7ac1e..fe3a1fba 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java +++ b/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java @@ -38,6 +38,7 @@ import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.topic.TopicValidator; import org.apache.rocketmq.dashboard.config.RMQConfigure; +import org.apache.rocketmq.dashboard.exception.ServiceException; import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest; import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo; import org.apache.rocketmq.dashboard.model.request.TopicTypeList; @@ -380,6 +381,9 @@ private TopicList getSystemTopicList() { @Override public SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest) { List topicConfigInfos = examineTopicConfig(sendTopicMessageRequest.getTopic()); + if (topicConfigInfos.isEmpty()) { + throw new ServiceException(-1, String.format("Topic [%s] has no broker route, cannot send message", sendTopicMessageRequest.getTopic())); + } String messageType = topicConfigInfos.get(0).getMessageType(); AclClientRPCHook rpcHook = null; if (configure.isACLEnabled()) { diff --git a/src/main/java/org/apache/rocketmq/dashboard/service/strategy/FileUserStrategy.java b/src/main/java/org/apache/rocketmq/dashboard/service/strategy/FileUserStrategy.java index d5dac403..524459d9 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/service/strategy/FileUserStrategy.java +++ b/src/main/java/org/apache/rocketmq/dashboard/service/strategy/FileUserStrategy.java @@ -94,7 +94,12 @@ public void load(InputStream inputStream) { } else if (arrs.length == 1) { role = 0; } else { - role = Integer.parseInt(arrs[1].trim()); + try { + role = Integer.parseInt(arrs[1].trim()); + } catch (NumberFormatException e) { + log.error("Invalid role '{}' for user '{}', defaulting to normal user", arrs[1].trim(), key); + role = 0; + } } loadUserMap.put(key, new User(key, arrs[0].trim(), role)); diff --git a/src/main/java/org/apache/rocketmq/dashboard/task/DashboardCollectTask.java b/src/main/java/org/apache/rocketmq/dashboard/task/DashboardCollectTask.java index ae50f5f2..14a4aaee 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/task/DashboardCollectTask.java +++ b/src/main/java/org/apache/rocketmq/dashboard/task/DashboardCollectTask.java @@ -127,7 +127,11 @@ public void collectBroker() { if (kvTable == null) { continue; } - String[] tpsArray = kvTable.getTable().get("getTotalTps").split(" "); + String totalTpsStr = kvTable.getTable().get("getTotalTps"); + if (totalTpsStr == null || totalTpsStr.trim().isEmpty()) { + continue; + } + String[] tpsArray = totalTpsStr.trim().split(" "); BigDecimal totalTps = new BigDecimal(0); for (String tps : tpsArray) { totalTps = totalTps.add(new BigDecimal(tps));