You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rocketmq.apache.org by li...@apache.org on 2026/08/07 05:51:56 UTC
(rocketmq-dashboard) branch rocketmq-studio updated: refactor: unify multi-vendor architecture and backend code style (#1231)
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 ceef946f refactor: unify multi-vendor architecture and backend code style (#1231)
ceef946f is described below
commit ceef946fa2908cf66469e478c5d84e14b9811253
Author: lizhimins <70...@qq.com>
AuthorDate: Fri Aug 7 13:51:50 2026 +0800
refactor: unify multi-vendor architecture and backend code style (#1231)
* refactor: unify controller contracts, remove dead and duplicate code, use HttpStatus enums
* refactor: converge multi-vendor architecture onto the instance provider SPI
* refactor: unify backend code style with lombok and consolidate instance-scoped packages
* chore: rename database to rocketmq and document server package structure
---
deploy/docker-compose.yml | 4 +-
deploy/mysql/init.sql | 4 +-
deploy/mysql/upgrade-cloud-vendor.sql | 2 +-
deploy/mysql/upgrade-demo-acl.sql | 2 +-
deploy/mysql/upgrade-demo-alert.sql | 2 +-
deploy/mysql/upgrade-demo-instance.sql | 2 +-
deploy/mysql/upgrade-query-history-context.sql | 2 +-
server/README.md | 108 ++++
.../studio/cloud/credential/CloudCredentialVO.java | 102 ----
.../studio/cluster/broker/ClusterService.java | 2 +-
.../cluster/k8s/MybatisPlusK8sCertRepository.java | 7 +-
.../cluster/metrics/MetricsSourceFactory.java | 7 +-
.../cluster/metrics/MetricsSourceSettings.java | 105 +---
.../domain/DeleteRequestDTO.java} | 14 +-
.../rocketmq/studio/common/domain/PageResult.java | 7 +-
.../rocketmq/studio/common/domain/Result.java | 7 +-
.../common/exception/GlobalExceptionHandler.java | 6 +-
.../studio/common/util/CredentialUtils.java | 69 +++
.../CreateInstanceDTO.java} | 58 +--
.../studio/instance/InstanceController.java | 20 +-
.../studio/instance/InstanceRepository.java | 4 +
.../rocketmq/studio/instance/InstanceService.java | 35 +-
.../instance/MybatisPlusInstanceRepository.java | 82 ++-
...eleteRequestDTO.java => UpdateInstanceDTO.java} | 31 +-
.../studio/instance/acl/AclController.java | 5 +-
.../rocketmq/studio/instance/acl/AclService.java | 38 +-
.../instance/acl/MybatisPlusAclRepository.java | 33 +-
.../rocketmq/studio/instance/dlq/DLQService.java | 2 +-
.../instance/group/ConsumerDiagnosticsService.java | 3 +-
.../message}/QueryHistoryProperties.java | 2 +-
.../message}/QueryHistoryService.java | 2 +-
.../instance/topic/CloudMetadataProvider.java | 67 ---
.../studio/instance/topic/MetadataService.java | 103 ++--
.../studio/instance/topic/NameSrvAdminClient.java | 1 +
.../studio/instance/topic/NamespaceController.java | 39 --
.../apache/rocketmq/studio/model/ACLPolicy.java | 114 +----
.../org/apache/rocketmq/studio/model/ACLUser.java | 82 +--
.../rocketmq/studio/model/AccessControlList.java | 91 +---
.../rocketmq/studio/model/Acl2PolicyContext.java | 154 +-----
.../rocketmq/studio/model/ClientInstance.java | 226 +--------
.../rocketmq/studio/model/ClusterCapability.java | 82 +--
.../rocketmq/studio/model/ClusterTopology.java | 116 +----
.../rocketmq/studio/model/ConsumerGroupInfo.java | 138 +-----
.../studio/model/ConsumerMonitorConfig.java | 31 +-
.../org/apache/rocketmq/studio/model/Entry.java | 36 +-
.../rocketmq/studio/model/LiteTopicQuota.java | 66 +--
.../rocketmq/studio/model/LiteTopicSession.java | 139 +-----
.../rocketmq/studio/model/LiteTopicSummary.java | 90 +---
.../apache/rocketmq/studio/model/LoginInfo.java | 19 +-
.../apache/rocketmq/studio/model/LoginResult.java | 26 +-
.../apache/rocketmq/studio/model/MessageInfo.java | 108 +---
.../studio/model/MetricsDataSourceConfig.java | 93 +---
.../rocketmq/studio/model/MetricsHealthResult.java | 45 +-
.../org/apache/rocketmq/studio/model/Policy.java | 19 +-
.../rocketmq/studio/model/PolicyRequest.java | 35 +-
.../rocketmq/studio/model/SubscriptionInfo.java | 82 +--
.../apache/rocketmq/studio/model/TopicInfo.java | 146 +-----
.../org/apache/rocketmq/studio/model/User.java | 47 +-
.../org/apache/rocketmq/studio/model/UserInfo.java | 45 +-
.../model/request/ArchitectureSwitchRequest.java | 29 +-
.../studio/model/request/MessageQuery.java | 51 +-
.../request/MetricsDataSourceQueryRequest.java | 34 +-
.../model/request/MetricsDataSourceRequest.java | 106 +---
.../studio/model/request/ResetOffsetRequest.java | 34 +-
.../model/request/SendTopicMessageRequest.java | 42 +-
.../studio/model/request/TopicTypeList.java | 18 +-
.../studio/model/request/TopicTypeMeta.java | 19 +-
.../studio/model/request/UserCreateRequest.java | 26 +-
.../studio/model/request/UserInfoParam.java | 34 +-
.../studio/model/request/UserUpdateRequest.java | 26 +-
.../studio/model/trace/MessageTraceGraph.java | 28 +-
.../rocketmq/studio/model/trace/ProducerNode.java | 67 +--
.../studio/model/trace/SubscriptionNode.java | 19 +-
.../rocketmq/studio/model/trace/TraceNode.java | 98 +---
.../rocketmq/studio/ops/ai/LlmConfigDTO.java | 51 ++
.../rocketmq/studio/ops/ai/LlmConfigService.java | 25 +-
.../rocketmq/studio/ops/ai/LlmController.java | 19 +-
.../rocketmq/studio/ops/ai/tool/ToolCatalog.java | 16 +-
.../ops/alert/MybatisPlusAlertRepository.java | 7 +-
.../ops/audit/MybatisPlusAuditRepository.java | 6 +-
.../persistence/entity/RmqCloudCredential.java | 66 +--
.../studio/provider/CloudInstanceDetailVO.java | 79 +--
.../studio/provider/CloudInstanceOptionVO.java | 59 +--
.../rocketmq/studio/provider/CloudRegionVO.java | 31 +-
.../rocketmq/studio/provider/InstanceProvider.java | 4 +
.../provider/alibaba/AliyunCatalogController.java | 6 +-
.../provider/alibaba/AliyunCatalogService.java | 6 +-
.../provider/alibaba/AliyunClientFactory.java | 16 +-
.../provider/alibaba/AliyunInstanceProvider.java | 51 +-
.../topic => provider/apache}/AdminClient.java | 5 +-
.../provider/apache/ApacheInstanceProvider.java | 24 +-
.../apache}/MetadataProvider.java | 5 +-
.../provider/apache/RocketMQAdminClientImpl.java | 528 ++++++++++++++++++++
.../apache}/RocketMQBrokerConfigService.java | 65 +--
.../apache}/RocketMQClientProvider.java | 76 ++-
.../apache}/RocketMQClusterProvider.java | 109 ++--
.../apache}/RocketMQDLQProvider.java | 16 +-
.../apache}/RocketMQDashboardProvider.java | 40 +-
.../apache}/RocketMQMessageProvider.java | 24 +-
.../apache}/RocketMQMetadataProvider.java | 376 ++++++--------
.../apache}/RocketMQProperties.java | 4 +-
.../apache}/ShortLivedClientName.java | 2 +-
.../credential/CloudCredentialController.java | 11 +-
.../credential/CloudCredentialRepository.java | 2 +-
.../credential/CloudCredentialService.java | 50 +-
.../credential/CloudCredentialVO.java} | 14 +-
.../credential/CreateCloudCredentialDTO.java | 44 +-
.../MybatisPlusCloudCredentialRepository.java | 34 +-
.../credential/UpdateCloudCredentialDTO.java} | 16 +-
.../provider/tencent/TencentInstanceProvider.java | 10 +
.../studio/rocketmq/RocketMQAdminClientImpl.java | 550 ---------------------
.../studio/rocketmq/RocketMQAdminConfig.java | 44 --
.../DataSourceDTO.java} | 35 +-
.../studio/settings/SettingsController.java | 15 +-
server/src/main/resources/application-dev.yml | 2 +-
server/src/main/resources/application.yml | 2 +-
.../studio/cluster/broker/ClusterServiceTest.java | 2 +-
.../studio/instance/InstanceControllerTest.java | 4 +-
.../studio/instance/InstanceServiceTest.java | 53 +-
.../MybatisPlusInstanceRepositoryTest.java | 43 +-
.../message}/QueryHistoryServiceTest.java | 2 +-
.../instance/topic/CloudMetadataProviderTest.java | 43 --
.../studio/instance/topic/MetadataServiceTest.java | 42 +-
.../instance/topic/NamespaceControllerTest.java | 53 --
.../org/apache/rocketmq/studio/model/UserTest.java | 4 +-
.../rocketmq/studio/ops/ai/LlmControllerTest.java | 27 +-
.../provider/alibaba/AliyunClientFactoryTest.java | 4 +-
.../alibaba/AliyunInstanceProviderTest.java | 39 ++
.../apache/ApacheInstanceProviderTest.java | 67 +++
.../apache}/RocketMQAdminClientImplTest.java | 11 +-
.../apache}/RocketMQClientProviderTest.java | 15 +-
.../apache}/RocketMQClusterProviderTest.java | 26 +-
.../apache}/RocketMQDLQProviderTest.java | 2 +-
.../apache}/RocketMQDashboardProviderTest.java | 22 +-
.../apache}/RocketMQMessageProviderTest.java | 11 +-
.../apache}/RocketMQMetadataProviderTest.java | 19 +-
.../apache}/ShortLivedClientNameTest.java | 2 +-
.../credential/CloudCredentialServiceTest.java | 9 +-
.../tencent/TencentInstanceProviderTest.java | 4 +
.../studio/settings/SettingsControllerTest.java | 4 +-
web/src/api/llm.test.ts | 51 +-
web/src/api/llm.ts | 16 +-
142 files changed, 1938 insertions(+), 4820 deletions(-)
diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml
index e7883c06..9c08c7e0 100644
--- a/deploy/docker-compose.yml
+++ b/deploy/docker-compose.yml
@@ -8,7 +8,7 @@ services:
environment:
TZ: ${TZ:-Asia/Shanghai}
MYSQL_ROOT_PASSWORD: studio123
- MYSQL_DATABASE: rocketmq_studio
+ MYSQL_DATABASE: rocketmq
ports:
- "3306:3306"
volumes:
@@ -41,7 +41,7 @@ services:
STUDIO_METRICS_PROMETHEUS_PASSWORD: ${STUDIO_METRICS_PROMETHEUS_PASSWORD:-}
STUDIO_METRICS_PROMETHEUS_BEARER_TOKEN: ${STUDIO_METRICS_PROMETHEUS_BEARER_TOKEN:-}
SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-prod}
- SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/rocketmq_studio?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&connectionCollation=utf8mb4_unicode_ci
+ SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/rocketmq?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&connectionCollation=utf8mb4_unicode_ci
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: studio123
STUDIO_ROCKETMQ_NAMESRV_ADDR: ${STUDIO_ROCKETMQ_NAMESRV_ADDR:-nameserver:9876}
diff --git a/deploy/mysql/init.sql b/deploy/mysql/init.sql
index 51b52ac6..f361c4d3 100644
--- a/deploy/mysql/init.sql
+++ b/deploy/mysql/init.sql
@@ -1,4 +1,4 @@
SET NAMES utf8mb4;
-CREATE DATABASE IF NOT EXISTS rocketmq_studio DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-USE rocketmq_studio;
+CREATE DATABASE IF NOT EXISTS rocketmq DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+USE rocketmq;
SOURCE /docker-entrypoint-initdb.d/schema.sql;
diff --git a/deploy/mysql/upgrade-cloud-vendor.sql b/deploy/mysql/upgrade-cloud-vendor.sql
index 8286a1bb..26684247 100644
--- a/deploy/mysql/upgrade-cloud-vendor.sql
+++ b/deploy/mysql/upgrade-cloud-vendor.sql
@@ -5,7 +5,7 @@
-- 幂等:可重复执行。
--
-- 用法(远程容器内执行):
--- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq_studio < upgrade-cloud-vendor.sql
+-- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < upgrade-cloud-vendor.sql
-- 固定连接编码,防止 mysql 客户端以 latin1 解释 UTF-8 字节导致中文双重编码
SET NAMES utf8mb4;
diff --git a/deploy/mysql/upgrade-demo-acl.sql b/deploy/mysql/upgrade-demo-acl.sql
index 75005217..acdbbd25 100644
--- a/deploy/mysql/upgrade-demo-acl.sql
+++ b/deploy/mysql/upgrade-demo-acl.sql
@@ -5,7 +5,7 @@
-- 幂等:可重复执行。
--
-- 用法(远程容器内执行):
--- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq_studio < upgrade-demo-acl.sql
+-- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < upgrade-demo-acl.sql
-- 固定连接编码,防止 mysql 客户端以 latin1 解释 UTF-8 字节导致中文双重编码
SET NAMES utf8mb4;
diff --git a/deploy/mysql/upgrade-demo-alert.sql b/deploy/mysql/upgrade-demo-alert.sql
index 904be1f9..de524ade 100644
--- a/deploy/mysql/upgrade-demo-alert.sql
+++ b/deploy/mysql/upgrade-demo-alert.sql
@@ -5,7 +5,7 @@
-- 幂等:可重复执行。
--
-- 用法(远程容器内执行):
--- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq_studio < upgrade-demo-alert.sql
+-- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < upgrade-demo-alert.sql
-- 固定连接编码,防止 mysql 客户端以 latin1 解释 UTF-8 字节导致中文双重编码
SET NAMES utf8mb4;
diff --git a/deploy/mysql/upgrade-demo-instance.sql b/deploy/mysql/upgrade-demo-instance.sql
index 0df0a17b..1dc8e585 100644
--- a/deploy/mysql/upgrade-demo-instance.sql
+++ b/deploy/mysql/upgrade-demo-instance.sql
@@ -5,7 +5,7 @@
-- 幂等:可重复执行。
--
-- 用法(远程容器内执行):
--- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq_studio < upgrade-demo-instance.sql
+-- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < upgrade-demo-instance.sql
-- 固定连接编码,防止 mysql 客户端以 latin1 解释 UTF-8 字节导致中文双重编码
SET NAMES utf8mb4;
diff --git a/deploy/mysql/upgrade-query-history-context.sql b/deploy/mysql/upgrade-query-history-context.sql
index 8520db44..d7a9ae1e 100644
--- a/deploy/mysql/upgrade-query-history-context.sql
+++ b/deploy/mysql/upgrade-query-history-context.sql
@@ -3,7 +3,7 @@
-- Fresh volumes already receive these columns from server/src/main/resources/db/schema.sql.
--
-- Run once on existing deployments:
--- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq_studio < upgrade-query-history-context.sql
+-- docker exec -i rocketmq-studio-mysql mysql -uroot -pstudio123 rocketmq < upgrade-query-history-context.sql
SET @schema_name := DATABASE();
diff --git a/server/README.md b/server/README.md
new file mode 100644
index 00000000..ffca74e3
--- /dev/null
+++ b/server/README.md
@@ -0,0 +1,108 @@
+# RocketMQ Studio Server — 后端包结构
+
+Spring Boot 3.5 / Java 21 / MyBatis-Plus 单体后端,包根 `org.apache.rocketmq.studio`,
+入口 `StudioApplication`。全部源码约 367 个 Java 文件,按业务域划包,本文档描述各包职责与分层约定。
+
+## 顶层包总览
+
+```
+org.apache.rocketmq.studio
+├── StudioApplication # Spring Boot 入口
+├── auth # 登录认证与会话(10 文件)
+├── audit # 操作审计(1 文件)
+├── cluster # 集群域:拓扑/集群/Proxy/NameServer/指标/K8s(75 文件)
+├── common # 公共基础:domain/exception/util/config(26 文件)
+├── instance # 实例域:实例注册 + Topic/Group/消息/DLQ/ACL/查询历史(68 文件)
+├── model # 遗留共享模型(admin 客户端交互对象)(41 文件)
+├── ops # 运维域:AI 助手/告警/审计/Dashboard(73 文件)
+├── persistence # MyBatis-Plus 实体与 Mapper(32 文件)
+├── provider # 多厂商 SPI、实现与云凭据(apache/alibaba/tencent/credential)(32 文件)
+└── settings # 通用设置与数据源(9 文件)
+```
+
+## 各包职责
+
+### auth — 认证
+登录/登出、`AuthInterceptor`(读者/管理员两级权限,凭据 reveal 类 GET 接口强制 admin)、
+`AuthenticatedUserContext` 会话上下文。
+
+### cluster — 集群域
+| 子包 | 职责 |
+|---|---|
+| `cluster.broker` | 集群拓扑、Broker 配置读写、`MqAdminExtFactory`(按 namesrv 地址缓存 admin 客户端)、`RuntimeAdminClientResolver`(按实例 endpoint 解析) |
+| `cluster.nameserver` | NameServer 地址注册表 CRUD |
+| `cluster.proxy` | Proxy 节点管理(列表/重启/地址维护、兼容旧 `.do` 路径) |
+| `cluster.client` | 客户端连接信息 |
+| `cluster.metrics` | Prometheus 指标接入(多数据源、健康检查),`metrics.grafana` 子包提供 Grafana 面板嵌入 |
+| `cluster.k8s` | K8s 证书管理 |
+| `cluster.config` | Broker 配置更新 DTO/VO |
+
+### common — 公共基础
+- `common.domain`:`Result<T>` 统一响应包装、`PageResult`、`BaseEntity`(id/createdAt/updatedAt)、
+ `DeleteRequestDTO`(通用删除入参)、`enums/`(InstanceType、InstanceVendor、TopicType 等 17 个枚举)
+- `common.exception`:`BusinessException(code, msg)` + `GlobalExceptionHandler`(统一转 `Result`)
+- `common.util`:`CredentialUtils` 等共享工具
+- `common.config`:CORS / Web MVC 配置
+
+### instance — 实例域(核心业务)
+实例注册与实例维度的资源管理,REST 基路径 `/api/instances`、`/api/topics`、`/api/groups`、
+`/api/messages`、`/api/dlq`、`/api/instance-acl`:
+
+| 子包 | 职责 |
+|---|---|
+| `instance`(顶层) | 实例 CRUD;vendor 分支创建(APACHE 手填 endpoint / ALIYUN 经云目录选择 / TENCENT 501) |
+| `instance.topic` | Topic CRUD/路由/订阅者、`MetadataService`(按 instanceId 路由到 provider)、消息发送、LiteTopic 子系统 |
+| `instance.group` | 消费组 CRUD/进度/订阅/重置位点/诊断栈 |
+| `instance.message` | 消息查询与轨迹(`MessageProvider` SPI)、查询历史(与实例绑定,随实例上下文记录/回放) |
+| `instance.dlq` | 死信队列列表与重发(`DLQProvider` SPI) |
+| `instance.acl` | 实例 ACL 规则与用户(凭据打码/reveal 的先例实现) |
+
+### provider — 多厂商 SPI
+统一实例操作抽象,按实例 vendor 路由:
+- `InstanceProvider`:topic/group CRUD、进度、订阅、重置位点、消息查询、轨迹(首参均为 Studio 实例 id)
+- `CloudCatalogProvider`:云目录发现(列 region / 列云实例 / 实例详情)
+- `InstanceProviderRegistry`:vendor → provider 路由,`byInstanceId` 查实例分发
+- `provider.apache`:开源实现层——`MetadataProvider`/`AdminClient` 接口为本包内部 SPI,
+ `RocketMQMetadataProvider`/`RocketMQAdminClientImpl` 经 `MqAdminExtFactory`(按 namesrv 地址缓存、
+ 懒建连接)执行 admin 操作;`ApacheInstanceProvider` 委托这些 bean,开源行为零差异;
+ `RocketMQMessage/DLQ/Client/Cluster/DashboardProvider` 与 Broker 配置服务也在本包
+- `provider.alibaba`:阿里云 RocketMQ 5.x OpenAPI 完整实现(`AliyunClientFactory` 按
+ credential#region 缓存 AsyncClient、异常统一映射、`AliyunConverters` 集中模型转换、
+ `/api/cloud/aliyun/*` 目录端点)
+- `provider.tencent`:占位实现(全部 `UnsupportedOperationException` → 501)
+- `provider.credential`:云厂商凭据管理(`rmq_cloud_credential` 表 CRUD,`/api/cloud-credentials`):
+ vendor+access_key 唯一键,SK base64 存储,列表打码 + `/{id}/credentials` reveal 接口,
+ 编解码与打码统一走 `common.util.CredentialUtils`
+
+### settings / audit
+通用设置(`rmq_settings`)、外部数据源配置与连通性测试、写操作审计。
+
+## 分层与命名约定
+
+- **Controller → Service → Repository**:Controller 只做入参校验与 `Result` 包装;
+ Repository 接口 + `MybatisPlus*` 实现(含 entity↔VO 映射)
+- **入参/出参**:写操作入参统一 `Create/Update/Delete*DTO`(jakarta validation),
+ 出参统一 `*VO`;禁止写接口直接收 VO
+- **异常**:`BusinessException(400, msg)` 裸数字码(400/401/403/404/409/500/501/502/503/504),
+ `GlobalExceptionHandler` 统一转 `Result`
+- **返回值**:REST 一律 `Result<T>` 包装
+- **Lombok**:POJO `@Data`/`@Builder`/`@NoArgsConstructor`/`@AllArgsConstructor`,
+ 服务 `@RequiredArgsConstructor`,日志 `@Slf4j`
+- **SPI 模式**:跨实现的能力(消息、DLQ、诊断、Dashboard、多厂商)定义 Provider 接口,
+ 开源实现统一放 `provider/apache/`(admin 客户端经 `MqAdminExtFactory` 单轨获取),
+ 云厂商实现放 `provider/<vendor>/` 保持高内聚
+- **敏感字段**:VO 上 `@ToString.Exclude`;存储 base64(见 `CredentialUtils`);
+ 列表打码、reveal 接口 admin-only
+
+## 构建与测试
+
+```bash
+cd server
+mvn -B -ntp package -DskipTests # 构建(checkstyle 在 validate 阶段强制)
+mvn -B -ntp -T 32 test # 全量单测(752 个)
+```
+
+依赖纪律:RocketMQ 系依赖(`org.apache.rocketmq:*`)只用 Apache 开源版本(当前基线 5.5.0),
+禁止内部/商业版本号;禁用 `com.aliyun.openservices:ons-client`,客户端收发用开源
+`rocketmq-client`;云厂商管控面走 OpenAPI SDK(`alibabacloud-rocketmq20220801` /
+`tencentcloud-sdk-java-tdmq`)。
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialVO.java b/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialVO.java
deleted file mode 100644
index 275f29b2..00000000
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialVO.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.rocketmq.studio.cloud.credential;
-
-import org.apache.rocketmq.studio.common.domain.BaseEntity;
-import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
-
-import java.util.Objects;
-
-public class CloudCredentialVO extends BaseEntity {
-
- private String name;
- private InstanceVendor vendor;
- private String accessKey;
- private String secretKey;
- private String remark;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public InstanceVendor getVendor() {
- return vendor;
- }
-
- public void setVendor(InstanceVendor vendor) {
- this.vendor = vendor;
- }
-
- public String getAccessKey() {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey) {
- this.accessKey = accessKey;
- }
-
- public String getSecretKey() {
- return secretKey;
- }
-
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
-
- public String getRemark() {
- return remark;
- }
-
- public void setRemark(String remark) {
- this.remark = remark;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof CloudCredentialVO)) {
- return false;
- }
- CloudCredentialVO that = (CloudCredentialVO) o;
- return Objects.equals(getId(), that.getId())
- && Objects.equals(name, that.name)
- && vendor == that.vendor
- && Objects.equals(accessKey, that.accessKey)
- && Objects.equals(secretKey, that.secretKey)
- && Objects.equals(remark, that.remark)
- && Objects.equals(getCreatedAt(), that.getCreatedAt())
- && Objects.equals(getUpdatedAt(), that.getUpdatedAt());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getId(), name, vendor, accessKey, secretKey, remark,
- getCreatedAt(), getUpdatedAt());
- }
-
- @Override
- public String toString() {
- return "CloudCredentialVO{id=" + getId() + ", name=" + name + ", vendor=" + vendor
- + ", accessKey=" + accessKey + ", secretKey=****}";
- }
-}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterService.java b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterService.java
index a8099614..4b8c76ae 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/cluster/broker/ClusterService.java
@@ -31,7 +31,7 @@ import org.apache.rocketmq.studio.cluster.proxy.RestartProxyDTO;
import org.apache.rocketmq.studio.common.domain.enums.FlushDiskType;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.ops.audit.AuditService;
-import org.apache.rocketmq.studio.rocketmq.RocketMQBrokerConfigService;
+import org.apache.rocketmq.studio.provider.apache.RocketMQBrokerConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cluster/k8s/MybatisPlusK8sCertRepository.java b/server/src/main/java/org/apache/rocketmq/studio/cluster/k8s/MybatisPlusK8sCertRepository.java
index ba7be5db..686f4d1e 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cluster/k8s/MybatisPlusK8sCertRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/cluster/k8s/MybatisPlusK8sCertRepository.java
@@ -26,6 +26,7 @@ import org.apache.rocketmq.studio.persistence.entity.RmqK8sCertificate;
import org.apache.rocketmq.studio.persistence.mapper.RmqK8sCertificateMapper;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
@@ -36,17 +37,13 @@ import java.util.stream.Collectors;
* MySQL-backed K8s certificate repository. The SAN list is stored as a JSON
* array string.
*/
+@RequiredArgsConstructor
@Repository
public class MybatisPlusK8sCertRepository implements K8sCertRepository {
private final RmqK8sCertificateMapper certMapper;
private final ObjectMapper objectMapper;
- public MybatisPlusK8sCertRepository(RmqK8sCertificateMapper certMapper, ObjectMapper objectMapper) {
- this.certMapper = certMapper;
- this.objectMapper = objectMapper;
- }
-
@Override
public List<K8sCertVO> findAll() {
return certMapper.selectList(new QueryWrapper<RmqK8sCertificate>().orderByAsc("name")).stream()
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceFactory.java b/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceFactory.java
index 7e50172e..33fd391f 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceFactory.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceFactory.java
@@ -19,6 +19,7 @@ package org.apache.rocketmq.studio.cluster.metrics;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClient;
+import lombok.RequiredArgsConstructor;
import java.time.Duration;
@@ -30,17 +31,13 @@ import java.time.Duration;
* query/parse logic via {@link AbstractPrometheusCompatibleMetricsSource}.
* </p>
*/
+@RequiredArgsConstructor
@Component
public class MetricsSourceFactory {
private final RestClient.Builder restClientBuilder;
private final ObjectMapper objectMapper;
- public MetricsSourceFactory(RestClient.Builder restClientBuilder, ObjectMapper objectMapper) {
- this.restClientBuilder = restClientBuilder;
- this.objectMapper = objectMapper;
- }
-
public MetricsSource create(org.apache.rocketmq.studio.model.MetricsDataSourceConfig config) {
MetricsBackendType backendType = MetricsBackendType.fromProviderType(config.getProviderType());
MetricsSourceSettings settings = MetricsSourceSettings.builder()
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceSettings.java b/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceSettings.java
index 6e60146f..a38aa280 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceSettings.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/cluster/metrics/MetricsSourceSettings.java
@@ -16,6 +16,9 @@
*/
package org.apache.rocketmq.studio.cluster.metrics;
+import lombok.Builder;
+import lombok.Getter;
+
import java.time.Duration;
/**
@@ -26,108 +29,22 @@ import java.time.Duration;
* produced by {@link MetricsSourceFactory} from a data source configuration.
* </p>
*/
+@Getter
+@Builder
public class MetricsSourceSettings {
- private final MetricsBackendType backendType;
+ @Builder.Default
+ private final MetricsBackendType backendType = MetricsBackendType.PROMETHEUS;
private final String baseUrl;
- private final Duration connectTimeout;
- private final Duration readTimeout;
+ @Builder.Default
+ private final Duration connectTimeout = Duration.ofSeconds(3);
+ @Builder.Default
+ private final Duration readTimeout = Duration.ofSeconds(10);
private final String username;
private final String password;
private final String bearerToken;
- private MetricsSourceSettings(Builder builder) {
- this.backendType = builder.backendType;
- this.baseUrl = builder.baseUrl;
- this.connectTimeout = builder.connectTimeout;
- this.readTimeout = builder.readTimeout;
- this.username = builder.username;
- this.password = builder.password;
- this.bearerToken = builder.bearerToken;
- }
-
- public MetricsBackendType getBackendType() {
- return backendType;
- }
-
public String getQueryPath() {
return backendType.getQueryPath();
}
-
- public String getBaseUrl() {
- return baseUrl;
- }
-
- public Duration getConnectTimeout() {
- return connectTimeout;
- }
-
- public Duration getReadTimeout() {
- return readTimeout;
- }
-
- public String getUsername() {
- return username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public String getBearerToken() {
- return bearerToken;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private MetricsBackendType backendType = MetricsBackendType.PROMETHEUS;
- private String baseUrl;
- private Duration connectTimeout = Duration.ofSeconds(3);
- private Duration readTimeout = Duration.ofSeconds(10);
- private String username;
- private String password;
- private String bearerToken;
-
- public Builder backendType(MetricsBackendType backendType) {
- this.backendType = backendType;
- return this;
- }
-
- public Builder baseUrl(String baseUrl) {
- this.baseUrl = baseUrl;
- return this;
- }
-
- public Builder connectTimeout(Duration connectTimeout) {
- this.connectTimeout = connectTimeout;
- return this;
- }
-
- public Builder readTimeout(Duration readTimeout) {
- this.readTimeout = readTimeout;
- return this;
- }
-
- public Builder username(String username) {
- this.username = username;
- return this;
- }
-
- public Builder password(String password) {
- this.password = password;
- return this;
- }
-
- public Builder bearerToken(String bearerToken) {
- this.bearerToken = bearerToken;
- return this;
- }
-
- public MetricsSourceSettings build() {
- return new MetricsSourceSettings(this);
- }
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclDeleteRequestDTO.java b/server/src/main/java/org/apache/rocketmq/studio/common/domain/DeleteRequestDTO.java
similarity index 80%
copy from server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclDeleteRequestDTO.java
copy to server/src/main/java/org/apache/rocketmq/studio/common/domain/DeleteRequestDTO.java
index 2e051bb1..b01188ba 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclDeleteRequestDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/common/domain/DeleteRequestDTO.java
@@ -14,19 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.instance.acl;
+package org.apache.rocketmq.studio.common.domain;
import jakarta.validation.constraints.NotBlank;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Data;
-import lombok.NoArgsConstructor;
+/**
+ * Common delete-by-id request body shared by all delete endpoints.
+ */
@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class AclDeleteRequestDTO {
+public class DeleteRequestDTO {
+
@NotBlank(message = "id is required")
private String id;
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/common/domain/PageResult.java b/server/src/main/java/org/apache/rocketmq/studio/common/domain/PageResult.java
index 5f11e861..ae7507cd 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/common/domain/PageResult.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/common/domain/PageResult.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.common.domain;
+import lombok.Getter;
import java.util.Collections;
import java.util.List;
+@Getter
public class PageResult<T> {
private List<T> items;
private long total;
@@ -39,9 +41,4 @@ public class PageResult<T> {
public static <T> PageResult<T> empty(int page, int size) {
return of(Collections.emptyList(), 0, page, size);
}
-
- public List<T> getItems() { return items; }
- public long getTotal() { return total; }
- public int getPage() { return page; }
- public int getSize() { return size; }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/common/domain/Result.java b/server/src/main/java/org/apache/rocketmq/studio/common/domain/Result.java
index d86705fc..2e09bdf2 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/common/domain/Result.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/common/domain/Result.java
@@ -16,6 +16,9 @@
*/
package org.apache.rocketmq.studio.common.domain;
+import lombok.Getter;
+
+@Getter
public class Result<T> {
private int code;
private String message;
@@ -40,8 +43,4 @@ public class Result<T> {
public static <T> Result<T> error(int code, String message) {
return new Result<>(code, message, null);
}
-
- public int getCode() { return code; }
- public String getMessage() { return message; }
- public T getData() { return data; }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/common/exception/GlobalExceptionHandler.java b/server/src/main/java/org/apache/rocketmq/studio/common/exception/GlobalExceptionHandler.java
index 98297fc5..384c16a6 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/common/exception/GlobalExceptionHandler.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/common/exception/GlobalExceptionHandler.java
@@ -19,8 +19,6 @@ package org.apache.rocketmq.studio.common.exception;
import org.apache.rocketmq.studio.cluster.metrics.PrometheusException;
import org.apache.rocketmq.studio.common.domain.Result;
import org.apache.rocketmq.studio.ops.ai.LlmGatewayException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
@@ -30,12 +28,12 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
- private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
-
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Result<?>> handleBusinessException(BusinessException ex) {
log.warn("Business exception: {}", ex.getMessage());
diff --git a/server/src/main/java/org/apache/rocketmq/studio/common/util/CredentialUtils.java b/server/src/main/java/org/apache/rocketmq/studio/common/util/CredentialUtils.java
new file mode 100644
index 00000000..f665f800
--- /dev/null
+++ b/server/src/main/java/org/apache/rocketmq/studio/common/util/CredentialUtils.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.rocketmq.studio.common.util;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+/**
+ * Shared credential helpers: secrets are stored base64-encoded (never plain text) and only
+ * partially shown in list views.
+ */
+public final class CredentialUtils {
+
+ private static final int VISIBLE_CREDENTIAL_CHARS = 4;
+ private static final int MIN_PARTIALLY_MASKED_CREDENTIAL_CHARS = 17;
+ private static final String CREDENTIAL_MASK = "****";
+
+ private CredentialUtils() {
+ }
+
+ public static String encodeBase64(String plainText) {
+ if (plainText == null) {
+ return null;
+ }
+ return Base64.getEncoder().encodeToString(plainText.getBytes(StandardCharsets.UTF_8));
+ }
+
+ public static String decodeBase64(String stored) {
+ if (stored == null) {
+ return null;
+ }
+ try {
+ return new String(Base64.getDecoder().decode(stored), StandardCharsets.UTF_8);
+ } catch (IllegalArgumentException ex) {
+ // tolerate legacy values that were stored without encoding
+ return stored;
+ }
+ }
+
+ /**
+ * Keeps the first and last few characters visible, hides everything else; short values are
+ * fully masked.
+ */
+ public static String mask(String value) {
+ if (value == null || value.isEmpty()) {
+ return value;
+ }
+ if (value.length() < MIN_PARTIALLY_MASKED_CREDENTIAL_CHARS) {
+ return CREDENTIAL_MASK;
+ }
+ return value.substring(0, VISIBLE_CREDENTIAL_CHARS)
+ + CREDENTIAL_MASK
+ + value.substring(value.length() - VISIBLE_CREDENTIAL_CHARS);
+ }
+}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/UpdateCloudCredentialDTO.java b/server/src/main/java/org/apache/rocketmq/studio/instance/CreateInstanceDTO.java
similarity index 50%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/UpdateCloudCredentialDTO.java
rename to server/src/main/java/org/apache/rocketmq/studio/instance/CreateInstanceDTO.java
index 067c58f6..f338dd16 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/UpdateCloudCredentialDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/CreateInstanceDTO.java
@@ -14,50 +14,42 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.instance;
-import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
+import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
-public class UpdateCloudCredentialDTO {
-
- @NotBlank(message = "credential id is required")
- private String id;
+@Data
+public class CreateInstanceDTO {
private String name;
- private String secretKey;
-
- private String remark;
-
- public String getId() {
- return id;
- }
+ private InstanceType type;
- public void setId(String id) {
- this.id = id;
- }
+ private String endpoint;
- public String getName() {
- return name;
- }
+ private String remark;
- public void setName(String name) {
- this.name = name;
- }
+ private InstanceVendor vendor;
- public String getSecretKey() {
- return secretKey;
- }
+ private String cloudInstanceId;
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
+ private String credentialId;
- public String getRemark() {
- return remark;
- }
+ private String regionId;
- public void setRemark(String remark) {
- this.remark = remark;
+ public InstanceVO toInstanceVO() {
+ InstanceVO vo = InstanceVO.builder()
+ .name(name)
+ .type(type)
+ .endpoint(endpoint)
+ .remark(remark)
+ .vendor(vendor)
+ .cloudInstanceId(cloudInstanceId)
+ .credentialId(credentialId)
+ .regionId(regionId)
+ .build();
+ return vo;
}
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceController.java b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceController.java
index ff9d0e83..ec480a75 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceController.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceController.java
@@ -17,9 +17,9 @@
package org.apache.rocketmq.studio.instance;
+import org.apache.rocketmq.studio.common.domain.DeleteRequestDTO;
import org.apache.rocketmq.studio.common.domain.Result;
import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
-import org.apache.rocketmq.studio.common.exception.BusinessException;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
@@ -46,26 +46,18 @@ public class InstanceController {
}
@PostMapping("/create")
- public Result<InstanceVO> createInstance(@RequestBody(required = false) InstanceVO instance) {
- requireInstance(instance);
- return Result.ok(instanceService.createInstance(instance));
+ public Result<InstanceVO> createInstance(@Valid @RequestBody CreateInstanceDTO request) {
+ return Result.ok(instanceService.createInstance(request.toInstanceVO()));
}
@PostMapping("/update")
- public Result<InstanceVO> updateInstance(@RequestBody(required = false) InstanceVO instance) {
- requireInstance(instance);
- return Result.ok(instanceService.updateInstance(instance));
+ public Result<InstanceVO> updateInstance(@Valid @RequestBody UpdateInstanceDTO request) {
+ return Result.ok(instanceService.updateInstance(request.toInstanceVO()));
}
@PostMapping("/delete")
- public Result<Void> deleteInstance(@Valid @RequestBody InstanceDeleteRequestDTO request) {
+ public Result<Void> deleteInstance(@Valid @RequestBody DeleteRequestDTO request) {
instanceService.deleteInstance(request.getId());
return Result.ok();
}
-
- private void requireInstance(InstanceVO instance) {
- if (instance == null) {
- throw new BusinessException(400, "Instance request is required");
- }
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
index f6c41f4d..546db9b6 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceRepository.java
@@ -38,4 +38,8 @@ public interface InstanceRepository {
void deleteById(String id);
boolean existsByCredentialId(String credentialId);
+
+ long countTopicsByInstance(String instanceId);
+
+ long countGroupsByInstance(String instanceId);
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
index 18b33e9e..95014da8 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
@@ -17,12 +17,15 @@
package org.apache.rocketmq.studio.instance;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialRepository;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialVO;
+import org.springframework.util.StringUtils;
+
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialRepository;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialVO;
import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.provider.CloudInstanceDetailVO;
+import org.apache.rocketmq.studio.provider.InstanceProvider;
import org.apache.rocketmq.studio.provider.InstanceProviderRegistry;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -55,25 +58,22 @@ public class InstanceService {
} else {
instances = instanceRepository.findAll();
}
- instances.forEach(this::fillCloudCounts);
+ instances.forEach(this::fillCounts);
return instances;
}
/**
- * Cloud instances keep topics/groups on the vendor side, so the local table counts are
- * always zero; pull live counts through the vendor provider instead.
+ * Resource counts live on the vendor side (cloud APIs) or in the local tables (Apache),
+ * so resolve them uniformly through the vendor provider.
*/
- private void fillCloudCounts(InstanceVO instance) {
- if (instance.getVendor() == null || instance.getVendor() == InstanceVendor.APACHE) {
- return;
- }
+ private void fillCounts(InstanceVO instance) {
+ InstanceVendor vendor = instance.getVendor() == null ? InstanceVendor.APACHE : instance.getVendor();
try {
- org.apache.rocketmq.studio.provider.InstanceProvider provider =
- providerRegistry.forVendor(instance.getVendor());
- instance.setTopicCount(provider.listTopics(instance.getId(), null, null).size());
- instance.setConsumerGroupCount(provider.listConsumerGroups(instance.getId(), null).size());
+ InstanceProvider provider = providerRegistry.forVendor(vendor);
+ instance.setTopicCount(provider.countTopics(instance.getId()));
+ instance.setConsumerGroupCount(provider.countGroups(instance.getId()));
} catch (RuntimeException ex) {
- log.warn("Failed to load cloud resource counts for instance {}: {}",
+ log.warn("Failed to load resource counts for instance {}: {}",
instance.getId(), ex.getMessage());
}
}
@@ -115,8 +115,8 @@ public class InstanceService {
if (instance.getEndpoint() != null && !instance.getEndpoint().isBlank()) {
throw new BusinessException(400, "Commercial instances must be selected from the cloud catalog, endpoint cannot be set manually");
}
- if (isBlank(instance.getCredentialId()) || isBlank(instance.getCloudInstanceId())
- || isBlank(instance.getRegionId())) {
+ if (!StringUtils.hasText(instance.getCredentialId()) || !StringUtils.hasText(instance.getCloudInstanceId())
+ || !StringUtils.hasText(instance.getRegionId())) {
throw new BusinessException(400, "credentialId, cloudInstanceId and regionId are required for Aliyun instances");
}
CloudCredentialVO credential = cloudCredentialRepository.findById(instance.getCredentialId())
@@ -157,9 +157,6 @@ public class InstanceService {
};
}
- private static boolean isBlank(String value) {
- return value == null || value.isBlank();
- }
public InstanceVO updateInstance(InstanceVO instance) {
requireInstance(instance);
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java b/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
index e903af4f..9d763926 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepository.java
@@ -27,13 +27,12 @@ import org.apache.rocketmq.studio.persistence.mapper.RmqGroupMapper;
import org.apache.rocketmq.studio.persistence.mapper.RmqInstanceMapper;
import org.apache.rocketmq.studio.persistence.mapper.RmqTopicMapper;
import org.springframework.stereotype.Repository;
+import lombok.RequiredArgsConstructor;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
-import java.util.stream.Collectors;
+@RequiredArgsConstructor
@Repository
public class MybatisPlusInstanceRepository implements InstanceRepository {
@@ -41,47 +40,47 @@ public class MybatisPlusInstanceRepository implements InstanceRepository {
private final RmqTopicMapper topicMapper;
private final RmqGroupMapper groupMapper;
- public MybatisPlusInstanceRepository(RmqInstanceMapper instanceMapper,
- RmqTopicMapper topicMapper,
- RmqGroupMapper groupMapper) {
- this.instanceMapper = instanceMapper;
- this.topicMapper = topicMapper;
- this.groupMapper = groupMapper;
- }
-
@Override
public List<InstanceVO> findAll() {
- return withCounts(instanceMapper.selectList(
- new QueryWrapper<RmqInstance>().orderByAsc("id")));
+ return instanceMapper.selectList(
+ new QueryWrapper<RmqInstance>().orderByAsc("id")).stream()
+ .map(this::toVO)
+ .toList();
}
@Override
public List<InstanceVO> findByType(InstanceType type) {
- return withCounts(instanceMapper.selectList(
+ return instanceMapper.selectList(
new QueryWrapper<RmqInstance>()
.eq("type", type.name())
- .orderByAsc("id")));
+ .orderByAsc("id")).stream()
+ .map(this::toVO)
+ .toList();
}
@Override
public List<InstanceVO> search(String keyword) {
- return withCounts(instanceMapper.selectList(
+ return instanceMapper.selectList(
new QueryWrapper<RmqInstance>()
.and(w -> w.like("name", keyword)
.or().like("endpoint", keyword)
.or().like("remark", keyword))
- .orderByAsc("id")));
+ .orderByAsc("id")).stream()
+ .map(this::toVO)
+ .toList();
}
@Override
public List<InstanceVO> findByTypeAndSearch(InstanceType type, String keyword) {
- return withCounts(instanceMapper.selectList(
+ return instanceMapper.selectList(
new QueryWrapper<RmqInstance>()
.eq("type", type.name())
.and(w -> w.like("name", keyword)
.or().like("endpoint", keyword)
.or().like("remark", keyword))
- .orderByAsc("id")));
+ .orderByAsc("id")).stream()
+ .map(this::toVO)
+ .toList();
}
@Override
@@ -90,13 +89,7 @@ public class MybatisPlusInstanceRepository implements InstanceRepository {
if (entity == null) {
return Optional.empty();
}
- Map<String, Long> topicCounts = countByInstance(topicMapper.selectMaps(
- new QueryWrapper<RmqTopic>().select("instance_id", "COUNT(*) AS total")
- .isNotNull("instance_id").eq("instance_id", id).groupBy("instance_id")));
- Map<String, Long> groupCounts = countByInstance(groupMapper.selectMaps(
- new QueryWrapper<RmqGroup>().select("instance_id", "COUNT(*) AS total")
- .isNotNull("instance_id").eq("instance_id", id).groupBy("instance_id")));
- return Optional.of(toVO(entity, topicCounts, groupCounts));
+ return Optional.of(toVO(entity));
}
@Override
@@ -124,36 +117,19 @@ public class MybatisPlusInstanceRepository implements InstanceRepository {
new QueryWrapper<RmqInstance>().eq("credential_id", credentialId)) > 0;
}
- private List<InstanceVO> withCounts(List<RmqInstance> entities) {
- if (entities.isEmpty()) {
- return List.of();
- }
- Map<String, Long> topicCounts = countByInstance(topicMapper.selectMaps(
- new QueryWrapper<RmqTopic>().select("instance_id", "COUNT(*) AS total")
- .isNotNull("instance_id").groupBy("instance_id")));
- Map<String, Long> groupCounts = countByInstance(groupMapper.selectMaps(
- new QueryWrapper<RmqGroup>().select("instance_id", "COUNT(*) AS total")
- .isNotNull("instance_id").groupBy("instance_id")));
- return entities.stream()
- .map(entity -> toVO(entity, topicCounts, groupCounts))
- .collect(Collectors.toList());
+ @Override
+ public long countTopicsByInstance(String instanceId) {
+ return topicMapper.selectCount(
+ new QueryWrapper<RmqTopic>().eq("instance_id", instanceId));
}
- private Map<String, Long> countByInstance(List<Map<String, Object>> rows) {
- Map<String, Long> counts = new HashMap<>();
- for (Map<String, Object> row : rows) {
- Object instanceId = row.get("instance_id");
- Object total = row.get("total");
- if (instanceId != null && total != null) {
- counts.put(instanceId.toString(), ((Number) total).longValue());
- }
- }
- return counts;
+ @Override
+ public long countGroupsByInstance(String instanceId) {
+ return groupMapper.selectCount(
+ new QueryWrapper<RmqGroup>().eq("instance_id", instanceId));
}
- private InstanceVO toVO(RmqInstance entity,
- Map<String, Long> topicCounts,
- Map<String, Long> groupCounts) {
+ private InstanceVO toVO(RmqInstance entity) {
InstanceVO vo = InstanceVO.builder()
.name(entity.getName())
.remark(entity.getRemark())
@@ -163,8 +139,6 @@ public class MybatisPlusInstanceRepository implements InstanceRepository {
.cloudInstanceId(entity.getCloudInstanceId())
.credentialId(entity.getCredentialId())
.regionId(entity.getRegionId())
- .topicCount(topicCounts.getOrDefault(entity.getId(), 0L).intValue())
- .consumerGroupCount(groupCounts.getOrDefault(entity.getId(), 0L).intValue())
.build();
vo.setId(entity.getId());
vo.setCreatedAt(entity.getCreatedAt());
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceDeleteRequestDTO.java b/server/src/main/java/org/apache/rocketmq/studio/instance/UpdateInstanceDTO.java
similarity index 63%
rename from server/src/main/java/org/apache/rocketmq/studio/instance/InstanceDeleteRequestDTO.java
rename to server/src/main/java/org/apache/rocketmq/studio/instance/UpdateInstanceDTO.java
index 418bf53f..6b94f840 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceDeleteRequestDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/UpdateInstanceDTO.java
@@ -17,16 +17,31 @@
package org.apache.rocketmq.studio.instance;
import jakarta.validation.constraints.NotBlank;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Data;
-import lombok.NoArgsConstructor;
+import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class InstanceDeleteRequestDTO {
- @NotBlank(message = "id is required")
+public class UpdateInstanceDTO {
+
+ @NotBlank(message = "instance id is required")
private String id;
+
+ private String name;
+
+ private InstanceType type;
+
+ private String endpoint;
+
+ private String remark;
+
+ public InstanceVO toInstanceVO() {
+ InstanceVO vo = InstanceVO.builder()
+ .name(name)
+ .type(type)
+ .endpoint(endpoint)
+ .remark(remark)
+ .build();
+ vo.setId(id);
+ return vo;
+ }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclController.java b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclController.java
index 4d25bf71..e02e8f10 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclController.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclController.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.instance.acl;
+import org.apache.rocketmq.studio.common.domain.DeleteRequestDTO;
import org.apache.rocketmq.studio.common.domain.Result;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import jakarta.validation.Valid;
@@ -55,7 +56,7 @@ public class AclController {
}
@PostMapping("/rules/delete")
- public Result<Void> deleteRule(@Valid @RequestBody AclDeleteRequestDTO request) {
+ public Result<Void> deleteRule(@Valid @RequestBody DeleteRequestDTO request) {
aclService.deleteRule(request.getId());
return Result.ok();
}
@@ -81,7 +82,7 @@ public class AclController {
}
@PostMapping("/users/delete")
- public Result<Void> deleteUser(@Valid @RequestBody AclDeleteRequestDTO request) {
+ public Result<Void> deleteUser(@Valid @RequestBody DeleteRequestDTO request) {
aclService.deleteUser(request.getId());
return Result.ok();
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java
index 65c7995e..c3ada9d7 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclService.java
@@ -16,7 +16,10 @@
*/
package org.apache.rocketmq.studio.instance.acl;
+import org.springframework.util.StringUtils;
+
import org.apache.rocketmq.studio.common.exception.BusinessException;
+import org.apache.rocketmq.studio.common.util.CredentialUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -30,10 +33,6 @@ import java.util.UUID;
@RequiredArgsConstructor
public class AclService {
- private static final int VISIBLE_CREDENTIAL_CHARS = 4;
- private static final int MIN_PARTIALLY_MASKED_CREDENTIAL_CHARS = 17;
- private static final String CREDENTIAL_MASK = "****";
-
private final AclRepository aclRepository;
@@ -45,10 +44,10 @@ public class AclService {
public AclRuleVO createRule(AclRuleVO rule) {
log.info("Creating ACL rule for principal={}", rule.getPrincipal());
- if (isBlank(rule.getPrincipal())) {
+ if (!StringUtils.hasText(rule.getPrincipal())) {
throw new BusinessException(400, "ACL principal is required");
}
- if (isBlank(rule.getResource())) {
+ if (!StringUtils.hasText(rule.getResource())) {
throw new BusinessException(400, "ACL resource is required");
}
rule.setId(UUID.randomUUID().toString());
@@ -57,7 +56,7 @@ public class AclService {
}
public AclRuleVO updateRule(AclRuleVO rule) {
- if (isBlank(rule.getId())) {
+ if (!StringUtils.hasText(rule.getId())) {
throw new BusinessException(400, "ACL rule id is required");
}
log.info("Updating ACL rule id={}, principal={}", rule.getId(), rule.getPrincipal());
@@ -83,7 +82,7 @@ public class AclService {
public AclUserVO createUser(AclUserVO user) {
log.info("Creating ACL user username={}", user.getUsername());
- if (isBlank(user.getUsername())) {
+ if (!StringUtils.hasText(user.getUsername())) {
throw new BusinessException(400, "ACL username is required");
}
user.setId(UUID.randomUUID().toString());
@@ -94,7 +93,7 @@ public class AclService {
}
public AclUserVO updateUser(UpdateAclUserDTO user) {
- if (isBlank(user.getId())) {
+ if (!StringUtils.hasText(user.getId())) {
throw new BusinessException(400, "ACL user id is required");
}
log.info("Updating ACL user id={}, username={}", user.getId(), user.getUsername());
@@ -124,7 +123,7 @@ public class AclService {
* The secret is stored base64-encoded in the database and decoded here.
*/
public AclUserVO getUserCredentials(String id) {
- if (isBlank(id)) {
+ if (!StringUtils.hasText(id)) {
throw new BusinessException(400, "ACL user id is required");
}
log.info("Revealing credentials for ACL user id={}", id);
@@ -132,31 +131,16 @@ public class AclService {
.orElseThrow(() -> new BusinessException(404, "ACL user not found: " + id));
}
- private boolean isBlank(String value) {
- return value == null || value.trim().isEmpty();
- }
-
private AclUserVO maskCredentials(AclUserVO user) {
return AclUserVO.builder()
.id(user.getId())
.username(user.getUsername())
- .accessKey(maskCredential(user.getAccessKey()))
- .secretKey(maskCredential(user.getSecretKey()))
+ .accessKey(CredentialUtils.mask(user.getAccessKey()))
+ .secretKey(CredentialUtils.mask(user.getSecretKey()))
.admin(user.isAdmin())
.clusters(user.getClusters() == null ? null : List.copyOf(user.getClusters()))
.createdAt(user.getCreatedAt())
.build();
}
- private String maskCredential(String credential) {
- if (credential == null || credential.isEmpty()) {
- return credential;
- }
- if (credential.length() < MIN_PARTIALLY_MASKED_CREDENTIAL_CHARS) {
- return CREDENTIAL_MASK;
- }
- return credential.substring(0, VISIBLE_CREDENTIAL_CHARS)
- + CREDENTIAL_MASK
- + credential.substring(credential.length() - VISIBLE_CREDENTIAL_CHARS);
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/MybatisPlusAclRepository.java b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/MybatisPlusAclRepository.java
index 318dd6c1..2aeccfa7 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/MybatisPlusAclRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/acl/MybatisPlusAclRepository.java
@@ -17,16 +17,16 @@
package org.apache.rocketmq.studio.instance.acl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import org.apache.rocketmq.studio.common.util.CredentialUtils;
import org.apache.rocketmq.studio.persistence.entity.RmqAclRule;
import org.apache.rocketmq.studio.persistence.entity.RmqAclUser;
import org.apache.rocketmq.studio.persistence.mapper.RmqAclRuleMapper;
import org.apache.rocketmq.studio.persistence.mapper.RmqAclUserMapper;
import org.springframework.stereotype.Repository;
+import lombok.RequiredArgsConstructor;
-import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Arrays;
-import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -35,17 +35,13 @@ import java.util.stream.Collectors;
* MySQL-backed ACL repository. User passwords are stored base64-encoded in
* {@code rmq_acl_user.secret_key} and decoded when read; plain text is never persisted.
*/
+@RequiredArgsConstructor
@Repository
public class MybatisPlusAclRepository implements AclRepository {
private final RmqAclRuleMapper ruleMapper;
private final RmqAclUserMapper userMapper;
- public MybatisPlusAclRepository(RmqAclRuleMapper ruleMapper, RmqAclUserMapper userMapper) {
- this.ruleMapper = ruleMapper;
- this.userMapper = userMapper;
- }
-
@Override
public List<AclRuleVO> findRules(String clusterId, String principal) {
QueryWrapper<RmqAclRule> query = new QueryWrapper<RmqAclRule>()
@@ -153,7 +149,7 @@ public class MybatisPlusAclRepository implements AclRepository {
.id(entity.getId())
.username(entity.getUsername())
.accessKey(entity.getAccessKey())
- .secretKey(decodeBase64(entity.getSecretKey()))
+ .secretKey(CredentialUtils.decodeBase64(entity.getSecretKey()))
.admin(Boolean.TRUE.equals(entity.getAdmin()))
.clusters(splitCsv(entity.getClusters()))
.createdAt(entity.getCreatedAt())
@@ -165,7 +161,7 @@ public class MybatisPlusAclRepository implements AclRepository {
entity.setId(user.getId());
entity.setUsername(user.getUsername());
entity.setAccessKey(user.getAccessKey());
- entity.setSecretKey(encodeBase64(user.getSecretKey()));
+ entity.setSecretKey(CredentialUtils.encodeBase64(user.getSecretKey()));
entity.setAdmin(user.isAdmin());
entity.setClusters(user.getClusters() == null ? null : String.join(",", user.getClusters()));
entity.setCreatedAt(user.getCreatedAt());
@@ -182,23 +178,4 @@ public class MybatisPlusAclRepository implements AclRepository {
.filter(part -> !part.isEmpty())
.collect(Collectors.toList());
}
-
- private static String encodeBase64(String plainText) {
- if (plainText == null) {
- return null;
- }
- return Base64.getEncoder().encodeToString(plainText.getBytes(StandardCharsets.UTF_8));
- }
-
- private static String decodeBase64(String stored) {
- if (stored == null) {
- return null;
- }
- try {
- return new String(Base64.getDecoder().decode(stored), StandardCharsets.UTF_8);
- } catch (IllegalArgumentException ex) {
- // tolerate legacy values that were stored without encoding
- return stored;
- }
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQService.java b/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQService.java
index 674ac107..5923e474 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/dlq/DLQService.java
@@ -59,7 +59,7 @@ public class DLQService {
private void validateResendRequest(String groupName, Long startTime, Long endTime) {
if (!StringUtils.hasText(groupName)) {
- throw new BusinessException(HttpStatus.BAD_REQUEST.value(), "groupName is required");
+ throw new BusinessException(400, "groupName is required");
}
if ((startTime == null) != (endTime == null)) {
throw new BusinessException(
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/group/ConsumerDiagnosticsService.java b/server/src/main/java/org/apache/rocketmq/studio/instance/group/ConsumerDiagnosticsService.java
index 87e8f1db..7a8699b6 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/group/ConsumerDiagnosticsService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/group/ConsumerDiagnosticsService.java
@@ -19,7 +19,6 @@ package org.apache.rocketmq.studio.instance.group;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import lombok.RequiredArgsConstructor;
-import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -37,7 +36,7 @@ public class ConsumerDiagnosticsService {
private String normalizeRequired(String value, String fieldName) {
if (!StringUtils.hasText(value)) {
- throw new BusinessException(HttpStatus.BAD_REQUEST.value(), fieldName + " is required");
+ throw new BusinessException(400, fieldName + " is required");
}
return value.trim();
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryProperties.java b/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryProperties.java
similarity index 95%
rename from server/src/main/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryProperties.java
rename to server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryProperties.java
index 63387497..0f081ba4 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryProperties.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryProperties.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.queryhistory;
+package org.apache.rocketmq.studio.instance.message;
import lombok.Getter;
import lombok.Setter;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryService.java b/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
similarity index 99%
rename from server/src/main/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryService.java
rename to server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
index 90bad479..68b56d1c 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/message/QueryHistoryService.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.queryhistory;
+package org.apache.rocketmq.studio.instance.message;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/CloudMetadataProvider.java b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/CloudMetadataProvider.java
deleted file mode 100644
index 7ca6e000..00000000
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/CloudMetadataProvider.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.rocketmq.studio.instance.topic;
-
-import org.apache.rocketmq.studio.common.exception.BusinessException;
-import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
-import org.apache.rocketmq.studio.instance.group.QueueProgressVO;
-import org.apache.rocketmq.studio.instance.group.SubscriptionEntryVO;
-
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.List;
-
-/**
- * Stub metadata provider. Disabled in favor of RocketMQMetadataProvider.
- */
-@Slf4j
-public class CloudMetadataProvider implements MetadataProvider {
-
- @Override
- public List<TopicVO> listTopics(String clusterId, String type, String search) {
- throw new UnsupportedOperationException("Not implemented");
- }
-
- @Override
- public List<ConsumerGroupVO> listConsumerGroups(String clusterId, String search) {
- throw consumerGroupProviderUnavailable();
- }
-
- @Override
- public List<BrokerRouteVO> getTopicRoutes(String name) {
- throw new UnsupportedOperationException("Not implemented");
- }
-
- @Override
- public List<TopicConsumerVO> getTopicConsumers(String name) {
- throw new UnsupportedOperationException("Not implemented");
- }
-
- @Override
- public List<QueueProgressVO> getGroupProgress(String name) {
- throw consumerGroupProviderUnavailable();
- }
-
- @Override
- public List<SubscriptionEntryVO> getGroupSubscriptions(String name) {
- throw consumerGroupProviderUnavailable();
- }
-
- private BusinessException consumerGroupProviderUnavailable() {
- return new BusinessException(501, "Consumer group metadata provider is not configured");
- }
-}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
index 94093daf..04b80abe 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataService.java
@@ -16,6 +16,8 @@
*/
package org.apache.rocketmq.studio.instance.topic;
+import org.apache.rocketmq.studio.provider.apache.AdminClient;
+import org.apache.rocketmq.studio.provider.apache.MetadataProvider;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
@@ -29,7 +31,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
-import java.util.Optional;
@Slf4j
@Service
@@ -48,28 +49,24 @@ public class MetadataService {
}
public List<TopicVO> listTopics(String instanceId, String clusterId, String type, String search) {
- return providerFor(instanceId)
- .map(provider -> provider.listTopics(instanceId, normalizeFilter(type), normalizeFilter(search)))
- .orElseGet(() -> metadataProvider.listTopics(
- normalizeFilter(clusterId),
- normalizeFilter(type),
- normalizeFilter(search)));
+ if (isBlank(instanceId) && !isBlank(clusterId)) {
+ // legacy cluster-scoped read kept for AI tool handlers
+ return metadataProvider.listTopics(
+ normalizeFilter(clusterId), normalizeFilter(type), normalizeFilter(search));
+ }
+ return resolve(instanceId).listTopics(instanceId, normalizeFilter(type), normalizeFilter(search));
}
public TopicVO createTopic(TopicVO topic) {
requireTopic(topic);
- return providerFor(topic.getInstanceId())
- .map(provider -> provider.createTopic(topic.getInstanceId(), topic))
- .orElseGet(() -> adminClient.createTopic(topic));
+ return resolve(topic.getInstanceId()).createTopic(topic.getInstanceId(), topic);
}
public TopicVO updateTopic(TopicVO topic) {
requireTopic(topic);
- return providerFor(topic.getInstanceId())
- .map(provider -> provider.updateTopic(topic.getInstanceId(), topic))
- .orElseGet(() -> adminClient.updateTopic(topic));
+ return resolve(topic.getInstanceId()).updateTopic(topic.getInstanceId(), topic);
}
@@ -78,12 +75,7 @@ public class MetadataService {
}
public void deleteTopic(String instanceId, String name) {
- Optional<InstanceProvider> provider = providerFor(instanceId);
- if (provider.isPresent()) {
- provider.get().deleteTopic(instanceId, name);
- } else {
- adminClient.deleteTopic(name);
- }
+ resolve(instanceId).deleteTopic(instanceId, name);
}
@@ -92,8 +84,7 @@ public class MetadataService {
}
public List<BrokerRouteVO> getTopicRoutes(String instanceId, String name) {
- Optional<InstanceProvider> provider = providerFor(instanceId);
- if (provider.isPresent() && provider.get().vendor() != InstanceVendor.APACHE) {
+ if (resolve(instanceId).vendor() != InstanceVendor.APACHE) {
// broker routing does not apply to serverless cloud instances
return List.of();
}
@@ -106,19 +97,15 @@ public class MetadataService {
}
public List<TopicConsumerVO> getTopicConsumers(String instanceId, String name) {
- return providerFor(instanceId)
- .map(provider -> provider.getTopicConsumers(instanceId, name))
- .orElseGet(() -> metadataProvider.getTopicConsumers(name));
+ return resolve(instanceId).getTopicConsumers(instanceId, name);
}
public SendMessageVO sendMessage(SendMessageDTO request) {
requireSendMessageRequest(request);
- providerFor(request.getInstanceId()).ifPresent(provider -> {
- if (provider.vendor() != InstanceVendor.APACHE) {
- throw new BusinessException(501, "Sending messages is not supported for cloud instances");
- }
- });
+ if (resolve(request.getInstanceId()).vendor() != InstanceVendor.APACHE) {
+ throw new BusinessException(501, "Sending messages is not supported for cloud instances");
+ }
return adminClient.sendMessage(request);
}
@@ -130,10 +117,10 @@ public class MetadataService {
}
public List<ConsumerGroupVO> listConsumerGroups(String instanceId, String clusterId, String search) {
- return providerFor(instanceId)
- .map(provider -> provider.listConsumerGroups(instanceId, normalizeFilter(search)))
- .orElseGet(() -> metadataProvider.listConsumerGroups(
- normalizeFilter(clusterId), normalizeFilter(search)));
+ if (isBlank(instanceId) && !isBlank(clusterId)) {
+ return metadataProvider.listConsumerGroups(normalizeFilter(clusterId), normalizeFilter(search));
+ }
+ return resolve(instanceId).listConsumerGroups(instanceId, normalizeFilter(search));
}
@@ -142,11 +129,9 @@ public class MetadataService {
}
public ConsumerGroupVO getConsumerGroup(String instanceId, String name) {
- providerFor(instanceId).ifPresent(provider -> {
- if (provider.vendor() != InstanceVendor.APACHE) {
- throw new BusinessException(501, "Consumer group detail is not supported for cloud instances");
- }
- });
+ if (resolve(instanceId).vendor() != InstanceVendor.APACHE) {
+ throw new BusinessException(501, "Consumer group detail is not supported for cloud instances");
+ }
return adminClient.getConsumerGroup(name);
}
@@ -156,9 +141,7 @@ public class MetadataService {
}
public List<QueueProgressVO> getGroupProgress(String instanceId, String name) {
- return providerFor(instanceId)
- .map(provider -> provider.getGroupProgress(instanceId, name))
- .orElseGet(() -> metadataProvider.getGroupProgress(name));
+ return resolve(instanceId).getGroupProgress(instanceId, name);
}
@@ -167,16 +150,13 @@ public class MetadataService {
}
public List<SubscriptionEntryVO> getGroupSubscriptions(String instanceId, String name) {
- return providerFor(instanceId)
- .map(provider -> provider.getGroupSubscriptions(instanceId, name))
- .orElseGet(() -> metadataProvider.getGroupSubscriptions(name));
+ return resolve(instanceId).getGroupSubscriptions(instanceId, name);
}
public ConsumerGroupVO createConsumerGroup(ConsumerGroupVO group) {
- return providerFor(group == null ? null : group.getInstanceId())
- .map(provider -> provider.createConsumerGroup(group.getInstanceId(), group))
- .orElseGet(() -> adminClient.createConsumerGroup(group));
+ String instanceId = group == null ? null : group.getInstanceId();
+ return resolve(instanceId).createConsumerGroup(instanceId, group);
}
@@ -185,12 +165,7 @@ public class MetadataService {
}
public void deleteConsumerGroup(String instanceId, String name) {
- Optional<InstanceProvider> provider = providerFor(instanceId);
- if (provider.isPresent()) {
- provider.get().deleteConsumerGroup(instanceId, name);
- } else {
- adminClient.deleteConsumerGroup(name);
- }
+ resolve(instanceId).deleteConsumerGroup(instanceId, name);
}
@@ -199,23 +174,21 @@ public class MetadataService {
}
public void resetOffset(String instanceId, String name, long timestamp, String topic) {
- Optional<InstanceProvider> provider = providerFor(instanceId);
- if (provider.isPresent()) {
- provider.get().resetOffset(instanceId, name, timestamp, topic);
- } else {
- adminClient.resetOffset(name, timestamp, topic);
- }
+ resolve(instanceId).resetOffset(instanceId, name, timestamp, topic);
}
- // ── NamespaceVO ───────────────────────────────────────────────────
-
- public List<NamespaceVO> listNamespaces() {
- throw new BusinessException(501, "Namespace discovery is not implemented by the current metadata provider");
+ /**
+ * Every metadata operation goes through the provider registry; a blank instance id keeps the
+ * legacy global behavior by defaulting to the Apache provider.
+ */
+ private InstanceProvider resolve(String instanceId) {
+ return providerRegistry.byInstanceId(instanceId)
+ .orElseGet(() -> providerRegistry.forVendor(InstanceVendor.APACHE));
}
- private Optional<InstanceProvider> providerFor(String instanceId) {
- return providerRegistry.byInstanceId(instanceId);
+ private static boolean isBlank(String value) {
+ return value == null || value.isBlank();
}
private String normalizeFilter(String value) {
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NameSrvAdminClient.java b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NameSrvAdminClient.java
index 3fe8c189..f91765b2 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NameSrvAdminClient.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NameSrvAdminClient.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.instance.topic;
+import org.apache.rocketmq.studio.provider.apache.AdminClient;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NamespaceController.java b/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NamespaceController.java
deleted file mode 100644
index 3cc6cf5f..00000000
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NamespaceController.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.rocketmq.studio.instance.topic;
-
-import org.apache.rocketmq.studio.common.domain.Result;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-
-@RestController
-@RequestMapping("/api/namespaces")
-@RequiredArgsConstructor
-public class NamespaceController {
-
- private final MetadataService metadataService;
-
- @GetMapping
- public Result<List<NamespaceVO>> listNamespaces() {
- return Result.ok(metadataService.listNamespaces());
- }
-}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ACLPolicy.java b/server/src/main/java/org/apache/rocketmq/studio/model/ACLPolicy.java
index 808d5dd9..2c9bde04 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ACLPolicy.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ACLPolicy.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.Set;
+@Data
public class ACLPolicy {
private String policyId;
@@ -82,116 +84,4 @@ public class ACLPolicy {
return "ALLOW".equals(policyType);
}
- public String getPolicyId() {
- return policyId;
- }
-
- public void setPolicyId(String policyId) {
- this.policyId = policyId;
- }
-
- public String getPolicyName() {
- return policyName;
- }
-
- public void setPolicyName(String policyName) {
- this.policyName = policyName;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public Set<String> getUsers() {
- return users;
- }
-
- public void setUsers(Set<String> users) {
- this.users = users;
- }
-
- public Set<String> getResources() {
- return resources;
- }
-
- public void setResources(Set<String> resources) {
- this.resources = resources;
- }
-
- public Set<String> getActions() {
- return actions;
- }
-
- public void setActions(Set<String> actions) {
- this.actions = actions;
- }
-
- public String getPolicyType() {
- return policyType;
- }
-
- public void setPolicyType(String policyType) {
- this.policyType = policyType;
- }
-
- public Set<String> getIpWhiteList() {
- return ipWhiteList;
- }
-
- public void setIpWhiteList(Set<String> ipWhiteList) {
- this.ipWhiteList = ipWhiteList;
- }
-
- public Date getEffectiveTime() {
- return effectiveTime;
- }
-
- public void setEffectiveTime(Date effectiveTime) {
- this.effectiveTime = effectiveTime;
- }
-
- public Date getExpirationTime() {
- return expirationTime;
- }
-
- public void setExpirationTime(Date expirationTime) {
- this.expirationTime = expirationTime;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public Boolean getDefaultPolicy() {
- return defaultPolicy;
- }
-
- public void setDefaultPolicy(Boolean defaultPolicy) {
- this.defaultPolicy = defaultPolicy;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ACLUser.java b/server/src/main/java/org/apache/rocketmq/studio/model/ACLUser.java
index e7d850c5..8ace2ad1 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ACLUser.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ACLUser.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.Set;
+@Data
public class ACLUser {
private String userName;
@@ -58,84 +60,4 @@ public class ACLUser {
}
return ipWhiteList.contains(ip);
}
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- public String getAccessKey() {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey) {
- this.accessKey = accessKey;
- }
-
- public String getUserType() {
- return userType;
- }
-
- public void setUserType(String userType) {
- this.userType = userType;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
-
- public Date getLastLoginTime() {
- return lastLoginTime;
- }
-
- public void setLastLoginTime(Date lastLoginTime) {
- this.lastLoginTime = lastLoginTime;
- }
-
- public Set<String> getPolicyIds() {
- return policyIds;
- }
-
- public void setPolicyIds(Set<String> policyIds) {
- this.policyIds = policyIds;
- }
-
- public Set<String> getIpWhiteList() {
- return ipWhiteList;
- }
-
- public void setIpWhiteList(Set<String> ipWhiteList) {
- this.ipWhiteList = ipWhiteList;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/AccessControlList.java b/server/src/main/java/org/apache/rocketmq/studio/model/AccessControlList.java
index 9e85e9cf..f4e88b02 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/AccessControlList.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/AccessControlList.java
@@ -16,12 +16,14 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.List;
/**
* Access Control List model for ACL management.
* Represents the ACL configuration for a broker.
*/
+@Data
public class AccessControlList {
private String brokerAddr;
@@ -29,41 +31,10 @@ public class AccessControlList {
private List<AccessControlEntry> entries;
private long version;
- public String getBrokerAddr() {
- return brokerAddr;
- }
-
- public void setBrokerAddr(String brokerAddr) {
- this.brokerAddr = brokerAddr;
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public List<AccessControlEntry> getEntries() {
- return entries;
- }
-
- public void setEntries(List<AccessControlEntry> entries) {
- this.entries = entries;
- }
-
- public long getVersion() {
- return version;
- }
-
- public void setVersion(long version) {
- this.version = version;
- }
-
/**
* Individual access control entry within an ACL.
*/
+ @Data
public static class AccessControlEntry {
private String accessKey;
@@ -73,61 +44,5 @@ public class AccessControlList {
private String defaultGroupPerm;
private List<String> topicPerms;
private List<String> groupPerms;
-
- public String getAccessKey() {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey) {
- this.accessKey = accessKey;
- }
-
- public String getSecretKey() {
- return secretKey;
- }
-
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
-
- public String getAdmin() {
- return admin;
- }
-
- public void setAdmin(String admin) {
- this.admin = admin;
- }
-
- public String getDefaultTopicPerm() {
- return defaultTopicPerm;
- }
-
- public void setDefaultTopicPerm(String defaultTopicPerm) {
- this.defaultTopicPerm = defaultTopicPerm;
- }
-
- public String getDefaultGroupPerm() {
- return defaultGroupPerm;
- }
-
- public void setDefaultGroupPerm(String defaultGroupPerm) {
- this.defaultGroupPerm = defaultGroupPerm;
- }
-
- public List<String> getTopicPerms() {
- return topicPerms;
- }
-
- public void setTopicPerms(List<String> topicPerms) {
- this.topicPerms = topicPerms;
- }
-
- public List<String> getGroupPerms() {
- return groupPerms;
- }
-
- public void setGroupPerms(List<String> groupPerms) {
- this.groupPerms = groupPerms;
- }
}
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/Acl2PolicyContext.java b/server/src/main/java/org/apache/rocketmq/studio/model/Acl2PolicyContext.java
index 268b61af..1e0dcbb4 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/Acl2PolicyContext.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/Acl2PolicyContext.java
@@ -16,7 +16,10 @@
*/
package org.apache.rocketmq.studio.model;
-
+import lombok.AccessLevel;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
import java.util.Date;
import java.util.List;
@@ -30,6 +33,7 @@ import java.util.List;
*
* @see ACLPolicy
*/
+@Data
public class Acl2PolicyContext {
// ========== Base Fields (Compatible with ACL 1.0) ==========
@@ -41,6 +45,8 @@ public class Acl2PolicyContext {
private String secretKey;
/** Whether this is an admin user */
+ @Getter(AccessLevel.NONE)
+ @Setter(AccessLevel.NONE)
private boolean isAdmin;
/** IP whitelist patterns */
@@ -82,6 +88,7 @@ public class Acl2PolicyContext {
* Authorization Rule - defines what actions are allowed/denied on which resources.
* Supports wildcards in resource patterns following path pattern syntax.
*/
+ @Data
public static class AuthorizationRule {
/** Resource path pattern supporting wildcards (* matches any single level, ** matches all levels) */
@@ -118,46 +125,6 @@ public class Acl2PolicyContext {
rule.setPriority(0);
return rule;
}
-
- public String getResourcePattern() {
- return resourcePattern;
- }
-
- public void setResourcePattern(String resourcePattern) {
- this.resourcePattern = resourcePattern;
- }
-
- public List<String> getActions() {
- return actions;
- }
-
- public void setActions(List<String> actions) {
- this.actions = actions;
- }
-
- public String getEffect() {
- return effect;
- }
-
- public void setEffect(String effect) {
- this.effect = effect;
- }
-
- public int getPriority() {
- return priority;
- }
-
- public void setPriority(int priority) {
- this.priority = priority;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
}
/**
@@ -205,22 +172,6 @@ public class Acl2PolicyContext {
private boolean isValidBoundType(String type) {
return "USER".equals(type) || "GROUP".equals(type) || "SERVICE_ACCOUNT".equals(type);
}
- public String getAccessKey() {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey) {
- this.accessKey = accessKey;
- }
-
- public String getSecretKey() {
- return secretKey;
- }
-
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
-
public boolean isIsAdmin() {
return isAdmin;
}
@@ -228,93 +179,4 @@ public class Acl2PolicyContext {
public void setIsAdmin(boolean isAdmin) {
this.isAdmin = isAdmin;
}
-
- public List<String> getWhiteSet() {
- return whiteSet;
- }
-
- public void setWhiteSet(List<String> whiteSet) {
- this.whiteSet = whiteSet;
- }
-
- public String getPolicyName() {
- return policyName;
- }
-
- public void setPolicyName(String policyName) {
- this.policyName = policyName;
- }
-
- public String getBoundType() {
- return boundType;
- }
-
- public void setBoundType(String boundType) {
- this.boundType = boundType;
- }
-
- public String getBoundEntityId() {
- return boundEntityId;
- }
-
- public void setBoundEntityId(String boundEntityId) {
- this.boundEntityId = boundEntityId;
- }
-
- public List<AuthorizationRule> getRules() {
- return rules;
- }
-
- public void setRules(List<AuthorizationRule> rules) {
- this.rules = rules;
- }
-
- public boolean isEnabled() {
- return enabled;
- }
-
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public String getBrokerName() {
- return brokerName;
- }
-
- public void setBrokerName(String brokerName) {
- this.brokerName = brokerName;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ClientInstance.java b/server/src/main/java/org/apache/rocketmq/studio/model/ClientInstance.java
index e608ee81..5714914c 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ClientInstance.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ClientInstance.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.List;
+@Data
public class ClientInstance {
private String clientId;
@@ -146,228 +148,4 @@ public class ClientInstance {
private String consumptionMode; // PULL / PUSH / POP
private Boolean orderlyConsume;
}
- public String getClientId() {
- return clientId;
- }
-
- public void setClientId(String clientId) {
- this.clientId = clientId;
- }
-
- public String getClientAddress() {
- return clientAddress;
- }
-
- public void setClientAddress(String clientAddress) {
- this.clientAddress = clientAddress;
- }
-
- public ClientType getClientType() {
- return clientType;
- }
-
- public void setClientType(ClientType clientType) {
- this.clientType = clientType;
- }
-
- public List<String> getTopics() {
- return topics;
- }
-
- public void setTopics(List<String> topics) {
- this.topics = topics;
- }
-
- public String getClientSubType() {
- return clientSubType;
- }
-
- public void setClientSubType(String clientSubType) {
- this.clientSubType = clientSubType;
- }
-
- public String getLanguage() {
- return language;
- }
-
- public void setLanguage(String language) {
- this.language = language;
- }
-
- public String getSdkVersion() {
- return sdkVersion;
- }
-
- public void setSdkVersion(String sdkVersion) {
- this.sdkVersion = sdkVersion;
- }
-
- public ProtocolType getProtocolType() {
- return protocolType;
- }
-
- public void setProtocolType(ProtocolType protocolType) {
- this.protocolType = protocolType;
- }
-
- public String getEndpoint() {
- return endpoint;
- }
-
- public void setEndpoint(String endpoint) {
- this.endpoint = endpoint;
- }
-
- public Date getLastHeartbeatTime() {
- return lastHeartbeatTime;
- }
-
- public void setLastHeartbeatTime(Date lastHeartbeatTime) {
- this.lastHeartbeatTime = lastHeartbeatTime;
- }
-
- public boolean isActive() {
- return active;
- }
-
- public void setActive(boolean active) {
- this.active = active;
- }
-
- public Date getConnectTime() {
- return connectTime;
- }
-
- public void setConnectTime(Date connectTime) {
- this.connectTime = connectTime;
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- public void setInstanceName(String instanceName) {
- this.instanceName = instanceName;
- }
-
- public String getConsumerGroup() {
- return consumerGroup;
- }
-
- public void setConsumerGroup(String consumerGroup) {
- this.consumerGroup = consumerGroup;
- }
-
- public String getProducerGroup() {
- return producerGroup;
- }
-
- public void setProducerGroup(String producerGroup) {
- this.producerGroup = producerGroup;
- }
-
- public List<SubscriptionInfo> getSubscriptions() {
- return subscriptions;
- }
-
- public void setSubscriptions(List<SubscriptionInfo> subscriptions) {
- this.subscriptions = subscriptions;
- }
-
- public List<String> getPublishTopics() {
- return publishTopics;
- }
-
- public void setPublishTopics(List<String> publishTopics) {
- this.publishTopics = publishTopics;
- }
-
- public ConsumerProgress getConsumerProgress() {
- return consumerProgress;
- }
-
- public void setConsumerProgress(ConsumerProgress consumerProgress) {
- this.consumerProgress = consumerProgress;
- }
-
- public String getClientVersion() {
- return clientVersion;
- }
-
- public void setClientVersion(String clientVersion) {
- this.clientVersion = clientVersion;
- }
-
- public Boolean getVipChannelEnabled() {
- return vipChannelEnabled;
- }
-
- public void setVipChannelEnabled(Boolean vipChannelEnabled) {
- this.vipChannelEnabled = vipChannelEnabled;
- }
-
- public String getTelemetrySessionId() {
- return telemetrySessionId;
- }
-
- public void setTelemetrySessionId(String telemetrySessionId) {
- this.telemetrySessionId = telemetrySessionId;
- }
-
- public Boolean getLongConnectionActive() {
- return longConnectionActive;
- }
-
- public void setLongConnectionActive(Boolean longConnectionActive) {
- this.longConnectionActive = longConnectionActive;
- }
-
- public String getSettingsVersion() {
- return settingsVersion;
- }
-
- public void setSettingsVersion(String settingsVersion) {
- this.settingsVersion = settingsVersion;
- }
-
- public String getAuthFailureReason() {
- return authFailureReason;
- }
-
- public void setAuthFailureReason(String authFailureReason) {
- this.authFailureReason = authFailureReason;
- }
-
- public Boolean getPopEnabled() {
- return popEnabled;
- }
-
- public void setPopEnabled(Boolean popEnabled) {
- this.popEnabled = popEnabled;
- }
-
- public Integer getPendingAckCount() {
- return pendingAckCount;
- }
-
- public void setPendingAckCount(Integer pendingAckCount) {
- this.pendingAckCount = pendingAckCount;
- }
-
- public Integer getSubscriptionCount() {
- return subscriptionCount;
- }
-
- public void setSubscriptionCount(Integer subscriptionCount) {
- this.subscriptionCount = subscriptionCount;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ClusterCapability.java b/server/src/main/java/org/apache/rocketmq/studio/model/ClusterCapability.java
index 750dd85c..a24b09a7 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ClusterCapability.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ClusterCapability.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.HashSet;
import java.util.Set;
+@Data
public class ClusterCapability {
private boolean liteTopicSupported;
@@ -67,84 +69,4 @@ public class ClusterCapability {
}
return false;
}
- public boolean isLiteTopicSupported() {
- return liteTopicSupported;
- }
-
- public void setLiteTopicSupported(boolean liteTopicSupported) {
- this.liteTopicSupported = liteTopicSupported;
- }
-
- public boolean isPopConsumeSupported() {
- return popConsumeSupported;
- }
-
- public void setPopConsumeSupported(boolean popConsumeSupported) {
- this.popConsumeSupported = popConsumeSupported;
- }
-
- public boolean isAclV2Supported() {
- return aclV2Supported;
- }
-
- public void setAclV2Supported(boolean aclV2Supported) {
- this.aclV2Supported = aclV2Supported;
- }
-
- public boolean isGrpcClientSupported() {
- return grpcClientSupported;
- }
-
- public void setGrpcClientSupported(boolean grpcClientSupported) {
- this.grpcClientSupported = grpcClientSupported;
- }
-
- public boolean isDelayMessageSupported() {
- return delayMessageSupported;
- }
-
- public void setDelayMessageSupported(boolean delayMessageSupported) {
- this.delayMessageSupported = delayMessageSupported;
- }
-
- public boolean isTransactionMessageSupported() {
- return transactionMessageSupported;
- }
-
- public void setTransactionMessageSupported(boolean transactionMessageSupported) {
- this.transactionMessageSupported = transactionMessageSupported;
- }
-
- public boolean isFifoMessageSupported() {
- return fifoMessageSupported;
- }
-
- public void setFifoMessageSupported(boolean fifoMessageSupported) {
- this.fifoMessageSupported = fifoMessageSupported;
- }
-
- public String getArchitectureVersion() {
- return architectureVersion;
- }
-
- public void setArchitectureVersion(String architectureVersion) {
- this.architectureVersion = architectureVersion;
- }
-
- public String getRocketmqVersion() {
- return rocketmqVersion;
- }
-
- public void setRocketmqVersion(String rocketmqVersion) {
- this.rocketmqVersion = rocketmqVersion;
- }
-
- public Set<String> getExtendedCapabilities() {
- return extendedCapabilities;
- }
-
- public void setExtendedCapabilities(Set<String> extendedCapabilities) {
- this.extendedCapabilities = extendedCapabilities;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ClusterTopology.java b/server/src/main/java/org/apache/rocketmq/studio/model/ClusterTopology.java
index d6474409..7a1d88e1 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ClusterTopology.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ClusterTopology.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -25,6 +26,7 @@ import java.util.Map;
* Unified cluster topology model
* Hide differences between different cluster architectures
*/
+@Data
public class ClusterTopology {
/**
@@ -117,7 +119,7 @@ public class ClusterTopology {
.count();
}
-
+ @Data
public static class NodeInfo {
private String nodeName;
private Long nodeId;
@@ -140,117 +142,5 @@ public class ClusterTopology {
public boolean isOnline() {
return "ONLINE".equals(status);
}
-
- public String getNodeName() {
- return nodeName;
- }
-
- public void setNodeName(String nodeName) {
- this.nodeName = nodeName;
- }
-
- public Long getNodeId() {
- return nodeId;
- }
-
- public void setNodeId(Long nodeId) {
- this.nodeId = nodeId;
- }
-
- public String getNodeAddress() {
- return nodeAddress;
- }
-
- public void setNodeAddress(String nodeAddress) {
- this.nodeAddress = nodeAddress;
- }
-
- public String getNodeType() {
- return nodeType;
- }
-
- public void setNodeType(String nodeType) {
- this.nodeType = nodeType;
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public Long getVersion() {
- return version;
- }
-
- public void setVersion(Long version) {
- this.version = version;
- }
-
- public Map<String, Object> getMetadata() {
- return metadata;
- }
-
- public void setMetadata(Map<String, Object> metadata) {
- this.metadata = metadata;
- }
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public List<String> getNamesrvAddresses() {
- return namesrvAddresses;
- }
-
- public void setNamesrvAddresses(List<String> namesrvAddresses) {
- this.namesrvAddresses = namesrvAddresses;
- }
-
- public List<NodeInfo> getNamesrvNodes() {
- return namesrvNodes;
- }
-
- public void setNamesrvNodes(List<NodeInfo> namesrvNodes) {
- this.namesrvNodes = namesrvNodes;
- }
-
- public List<NodeInfo> getBrokerNodes() {
- return brokerNodes;
- }
-
- public void setBrokerNodes(List<NodeInfo> brokerNodes) {
- this.brokerNodes = brokerNodes;
- }
-
- public List<NodeInfo> getProxyNodes() {
- return proxyNodes;
- }
-
- public void setProxyNodes(List<NodeInfo> proxyNodes) {
- this.proxyNodes = proxyNodes;
- }
-
- public Map<String, NodeInfo> getNodeMap() {
- return nodeMap;
- }
-
- public void setNodeMap(Map<String, NodeInfo> nodeMap) {
- this.nodeMap = nodeMap;
}
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerGroupInfo.java b/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerGroupInfo.java
index db0b7500..61d4ab1e 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerGroupInfo.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerGroupInfo.java
@@ -16,10 +16,12 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.Map;
import java.util.Set;
+@Data
public class ConsumerGroupInfo {
private String consumerGroupName;
@@ -71,140 +73,4 @@ public class ConsumerGroupInfo {
public boolean isBroadcastConsume() {
return Boolean.TRUE.equals(consumeBroadcastEnable);
}
- public String getConsumerGroupName() {
- return consumerGroupName;
- }
-
- public void setConsumerGroupName(String consumerGroupName) {
- this.consumerGroupName = consumerGroupName;
- }
-
- public String getConsumeMode() {
- return consumeMode;
- }
-
- public void setConsumeMode(String consumeMode) {
- this.consumeMode = consumeMode;
- }
-
- public Boolean getConsumeMessageOrderly() {
- return consumeMessageOrderly;
- }
-
- public void setConsumeMessageOrderly(Boolean consumeMessageOrderly) {
- this.consumeMessageOrderly = consumeMessageOrderly;
- }
-
- public Boolean getConsumeBroadcastEnable() {
- return consumeBroadcastEnable;
- }
-
- public void setConsumeBroadcastEnable(Boolean consumeBroadcastEnable) {
- this.consumeBroadcastEnable = consumeBroadcastEnable;
- }
-
- public Boolean getConsumeFromMinEnable() {
- return consumeFromMinEnable;
- }
-
- public void setConsumeFromMinEnable(Boolean consumeFromMinEnable) {
- this.consumeFromMinEnable = consumeFromMinEnable;
- }
-
- public Integer getRetryQueueNums() {
- return retryQueueNums;
- }
-
- public void setRetryQueueNums(Integer retryQueueNums) {
- this.retryQueueNums = retryQueueNums;
- }
-
- public Integer getRetryMaxTimes() {
- return retryMaxTimes;
- }
-
- public void setRetryMaxTimes(Integer retryMaxTimes) {
- this.retryMaxTimes = retryMaxTimes;
- }
-
- public Integer getConsumeTimeoutMinute() {
- return consumeTimeoutMinute;
- }
-
- public void setConsumeTimeoutMinute(Integer consumeTimeoutMinute) {
- this.consumeTimeoutMinute = consumeTimeoutMinute;
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public Set<String> getSubscribedTopics() {
- return subscribedTopics;
- }
-
- public void setSubscribedTopics(Set<String> subscribedTopics) {
- this.subscribedTopics = subscribedTopics;
- }
-
- public Integer getOnlineClientCount() {
- return onlineClientCount;
- }
-
- public void setOnlineClientCount(Integer onlineClientCount) {
- this.onlineClientCount = onlineClientCount;
- }
-
- public String getLiteBindTopic() {
- return liteBindTopic;
- }
-
- public void setLiteBindTopic(String liteBindTopic) {
- this.liteBindTopic = liteBindTopic;
- }
-
- public Map<String, String> getAttributes() {
- return attributes;
- }
-
- public void setAttributes(Map<String, String> attributes) {
- this.attributes = attributes;
- }
-
- public Integer getGroupSysFlag() {
- return groupSysFlag;
- }
-
- public void setGroupSysFlag(Integer groupSysFlag) {
- this.groupSysFlag = groupSysFlag;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerMonitorConfig.java b/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerMonitorConfig.java
index 9bb74c3a..e905f0e6 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerMonitorConfig.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/ConsumerMonitorConfig.java
@@ -16,31 +16,14 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
public class ConsumerMonitorConfig {
private int minCount;
private int maxDiffTotal;
-
- public ConsumerMonitorConfig() {
- }
-
- public ConsumerMonitorConfig(int minCount, int maxDiffTotal) {
- this.minCount = minCount;
- this.maxDiffTotal = maxDiffTotal;
- }
-
- public int getMinCount() {
- return minCount;
- }
-
- public void setMinCount(int minCount) {
- this.minCount = minCount;
- }
-
- public int getMaxDiffTotal() {
- return maxDiffTotal;
- }
-
- public void setMaxDiffTotal(int maxDiffTotal) {
- this.maxDiffTotal = maxDiffTotal;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/Entry.java b/server/src/main/java/org/apache/rocketmq/studio/model/Entry.java
index 8b623ede..d8d3b505 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/Entry.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/Entry.java
@@ -17,45 +17,13 @@
package org.apache.rocketmq.studio.model;
-
+import lombok.Data;
import java.util.List;
+@Data
public class Entry {
private List<String> resource;
private List<String> actions;
private List<String> sourceIps;
private String decision;
-
- public List<String> getResource() {
- return resource;
- }
-
- public void setResource(List<String> resource) {
- this.resource = resource;
- }
-
- public List<String> getActions() {
- return actions;
- }
-
- public void setActions(List<String> actions) {
- this.actions = actions;
- }
-
- public List<String> getSourceIps() {
- return sourceIps;
- }
-
- public void setSourceIps(List<String> sourceIps) {
- this.sourceIps = sourceIps;
- }
-
- public String getDecision() {
- return decision;
- }
-
- public void setDecision(String decision) {
- this.decision = decision;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicQuota.java b/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicQuota.java
index daa39b8c..39fd47ab 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicQuota.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicQuota.java
@@ -16,7 +16,9 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
+@Data
public class LiteTopicQuota {
private Integer maxTopicCount;
@@ -63,68 +65,4 @@ public class LiteTopicQuota {
}
return Math.max(0, maxTopicCount - currentTopicCount);
}
- public Integer getMaxTopicCount() {
- return maxTopicCount;
- }
-
- public void setMaxTopicCount(Integer maxTopicCount) {
- this.maxTopicCount = maxTopicCount;
- }
-
- public Integer getCurrentTopicCount() {
- return currentTopicCount;
- }
-
- public void setCurrentTopicCount(Integer currentTopicCount) {
- this.currentTopicCount = currentTopicCount;
- }
-
- public Integer getMaxSessionCount() {
- return maxSessionCount;
- }
-
- public void setMaxSessionCount(Integer maxSessionCount) {
- this.maxSessionCount = maxSessionCount;
- }
-
- public Integer getCurrentSessionCount() {
- return currentSessionCount;
- }
-
- public void setCurrentSessionCount(Integer currentSessionCount) {
- this.currentSessionCount = currentSessionCount;
- }
-
- public Long getDefaultTTL() {
- return defaultTTL;
- }
-
- public void setDefaultTTL(Long defaultTTL) {
- this.defaultTTL = defaultTTL;
- }
-
- public Long getMaxTTL() {
- return maxTTL;
- }
-
- public void setMaxTTL(Long maxTTL) {
- this.maxTTL = maxTTL;
- }
-
- public Double getCurrentCreationRate() {
- return currentCreationRate;
- }
-
- public void setCurrentCreationRate(Double currentCreationRate) {
- this.currentCreationRate = currentCreationRate;
- }
-
- public Double getMaxCreationRate() {
- return maxCreationRate;
- }
-
- public void setMaxCreationRate(Double maxCreationRate) {
- this.maxCreationRate = maxCreationRate;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSession.java b/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSession.java
index f7ea3587..debbb8f4 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSession.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSession.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.Set;
+@Data
public class LiteTopicSession {
/**
@@ -76,6 +78,7 @@ public class LiteTopicSession {
return (double) consumedMessages / totalMessages * 100.0;
}
+ @Data
public static class PopConsumeProgress {
private Integer ackTimeoutSeconds;
private Integer maxReconsumeTimes;
@@ -84,140 +87,4 @@ public class LiteTopicSession {
private Integer popCheckpoint;
private Integer totalPopCount;
}
- public String getSessionId() {
- return sessionId;
- }
-
- public void setSessionId(String sessionId) {
- this.sessionId = sessionId;
- }
-
- public String getClientId() {
- return clientId;
- }
-
- public void setClientId(String clientId) {
- this.clientId = clientId;
- }
-
- public String getClientAddress() {
- return clientAddress;
- }
-
- public void setClientAddress(String clientAddress) {
- this.clientAddress = clientAddress;
- }
-
- public Set<String> getLiteTopics() {
- return liteTopics;
- }
-
- public void setLiteTopics(Set<String> liteTopics) {
- this.liteTopics = liteTopics;
- }
-
- public String getParentTopic() {
- return parentTopic;
- }
-
- public void setParentTopic(String parentTopic) {
- this.parentTopic = parentTopic;
- }
-
- public String getConsumerGroup() {
- return consumerGroup;
- }
-
- public void setConsumerGroup(String consumerGroup) {
- this.consumerGroup = consumerGroup;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getLastActiveTime() {
- return lastActiveTime;
- }
-
- public void setLastActiveTime(Date lastActiveTime) {
- this.lastActiveTime = lastActiveTime;
- }
-
- public Long getTtl() {
- return ttl;
- }
-
- public void setTtl(Long ttl) {
- this.ttl = ttl;
- }
-
- public Long getTtlRemaining() {
- return ttlRemaining;
- }
-
- public void setTtlRemaining(Long ttlRemaining) {
- this.ttlRemaining = ttlRemaining;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public Long getTotalMessages() {
- return totalMessages;
- }
-
- public void setTotalMessages(Long totalMessages) {
- this.totalMessages = totalMessages;
- }
-
- public Long getConsumedMessages() {
- return consumedMessages;
- }
-
- public void setConsumedMessages(Long consumedMessages) {
- this.consumedMessages = consumedMessages;
- }
-
- public Long getPendingMessages() {
- return pendingMessages;
- }
-
- public void setPendingMessages(Long pendingMessages) {
- this.pendingMessages = pendingMessages;
- }
-
- public Double getConsumptionRate() {
- return consumptionRate;
- }
-
- public void setConsumptionRate(Double consumptionRate) {
- this.consumptionRate = consumptionRate;
- }
-
- public PopConsumeProgress getPopProgress() {
- return popProgress;
- }
-
- public void setPopProgress(PopConsumeProgress popProgress) {
- this.popProgress = popProgress;
- }
-
- public Integer getLiteTopicCreationCount() {
- return liteTopicCreationCount;
- }
-
- public void setLiteTopicCreationCount(Integer liteTopicCreationCount) {
- this.liteTopicCreationCount = liteTopicCreationCount;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSummary.java b/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSummary.java
index 49447ac5..925c2dee 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSummary.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/LiteTopicSummary.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.List;
+@Data
public class LiteTopicSummary {
private String topicPattern;
@@ -72,92 +74,4 @@ public class LiteTopicSummary {
public boolean isEmptyAggregation() {
return consumerCount == 0 && (totalBacklog == null || totalBacklog == 0);
}
- public String getTopicPattern() {
- return topicPattern;
- }
-
- public void setTopicPattern(String topicPattern) {
- this.topicPattern = topicPattern;
- }
-
- public Integer getTopicCount() {
- return topicCount;
- }
-
- public void setTopicCount(Integer topicCount) {
- this.topicCount = topicCount;
- }
-
- public List<String> getSessionIds() {
- return sessionIds;
- }
-
- public void setSessionIds(List<String> sessionIds) {
- this.sessionIds = sessionIds;
- }
-
- public Date getEarliestCreateTime() {
- return earliestCreateTime;
- }
-
- public void setEarliestCreateTime(Date earliestCreateTime) {
- this.earliestCreateTime = earliestCreateTime;
- }
-
- public Date getLastActiveTime() {
- return lastActiveTime;
- }
-
- public void setLastActiveTime(Date lastActiveTime) {
- this.lastActiveTime = lastActiveTime;
- }
-
- public Long getAverageTTL() {
- return averageTTL;
- }
-
- public void setAverageTTL(Long averageTTL) {
- this.averageTTL = averageTTL;
- }
-
- public Long getMinTTL() {
- return minTTL;
- }
-
- public void setMinTTL(Long minTTL) {
- this.minTTL = minTTL;
- }
-
- public Long getMaxTTL() {
- return maxTTL;
- }
-
- public void setMaxTTL(Long maxTTL) {
- this.maxTTL = maxTTL;
- }
-
- public Integer getConsumerCount() {
- return consumerCount;
- }
-
- public void setConsumerCount(Integer consumerCount) {
- this.consumerCount = consumerCount;
- }
-
- public Long getTotalBacklog() {
- return totalBacklog;
- }
-
- public void setTotalBacklog(Long totalBacklog) {
- this.totalBacklog = totalBacklog;
- }
-
- public boolean isActive() {
- return active;
- }
-
- public void setActive(boolean active) {
- this.active = active;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/LoginInfo.java b/server/src/main/java/org/apache/rocketmq/studio/model/LoginInfo.java
index 189c6928..449fe7e5 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/LoginInfo.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/LoginInfo.java
@@ -17,23 +17,10 @@
package org.apache.rocketmq.studio.model;
+import lombok.Data;
+
+@Data
public class LoginInfo {
private boolean loginRequired;
private boolean logined;
-
- public boolean isLoginRequired() {
- return loginRequired;
- }
-
- public void setLoginRequired(boolean loginRequired) {
- this.loginRequired = loginRequired;
- }
-
- public boolean isLogined() {
- return logined;
- }
-
- public void setLogined(boolean logined) {
- this.logined = logined;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/LoginResult.java b/server/src/main/java/org/apache/rocketmq/studio/model/LoginResult.java
index 72eccf1f..12be8380 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/LoginResult.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/LoginResult.java
@@ -16,7 +16,9 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
+@Data
public class LoginResult {
private String loginUserName;
@@ -27,28 +29,4 @@ public class LoginResult {
private int loginUserRole;
private String contextPath;
- public String getLoginUserName() {
- return loginUserName;
- }
-
- public void setLoginUserName(String loginUserName) {
- this.loginUserName = loginUserName;
- }
-
- public int getLoginUserRole() {
- return loginUserRole;
- }
-
- public void setLoginUserRole(int loginUserRole) {
- this.loginUserRole = loginUserRole;
- }
-
- public String getContextPath() {
- return contextPath;
- }
-
- public void setContextPath(String contextPath) {
- this.contextPath = contextPath;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/MessageInfo.java b/server/src/main/java/org/apache/rocketmq/studio/model/MessageInfo.java
index 26c0f42b..91c90f7c 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/MessageInfo.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/MessageInfo.java
@@ -16,12 +16,14 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Map;
/**
* Message information model for message query and management.
* Encapsulates key message attributes for dashboard display.
*/
+@Data
public class MessageInfo {
private String msgId;
@@ -37,108 +39,4 @@ public class MessageInfo {
private Map<String, String> properties;
private boolean retryTopic;
private int reconsumeTimes;
-
- public String getMsgId() {
- return msgId;
- }
-
- public void setMsgId(String msgId) {
- this.msgId = msgId;
- }
-
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public String getBrokerName() {
- return brokerName;
- }
-
- public void setBrokerName(String brokerName) {
- this.brokerName = brokerName;
- }
-
- public int getQueueId() {
- return queueId;
- }
-
- public void setQueueId(int queueId) {
- this.queueId = queueId;
- }
-
- public long getQueueOffset() {
- return queueOffset;
- }
-
- public void setQueueOffset(long queueOffset) {
- this.queueOffset = queueOffset;
- }
-
- public long getStoreTimestamp() {
- return storeTimestamp;
- }
-
- public void setStoreTimestamp(long storeTimestamp) {
- this.storeTimestamp = storeTimestamp;
- }
-
- public long getBornTimestamp() {
- return bornTimestamp;
- }
-
- public void setBornTimestamp(long bornTimestamp) {
- this.bornTimestamp = bornTimestamp;
- }
-
- public String getKeys() {
- return keys;
- }
-
- public void setKeys(String keys) {
- this.keys = keys;
- }
-
- public String getTags() {
- return tags;
- }
-
- public void setTags(String tags) {
- this.tags = tags;
- }
-
- public String getBody() {
- return body;
- }
-
- public void setBody(String body) {
- this.body = body;
- }
-
- public Map<String, String> getProperties() {
- return properties;
- }
-
- public void setProperties(Map<String, String> properties) {
- this.properties = properties;
- }
-
- public boolean isRetryTopic() {
- return retryTopic;
- }
-
- public void setRetryTopic(boolean retryTopic) {
- this.retryTopic = retryTopic;
- }
-
- public int getReconsumeTimes() {
- return reconsumeTimes;
- }
-
- public void setReconsumeTimes(int reconsumeTimes) {
- this.reconsumeTimes = reconsumeTimes;
- }
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/MetricsDataSourceConfig.java b/server/src/main/java/org/apache/rocketmq/studio/model/MetricsDataSourceConfig.java
index f15400ae..da45e74e 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/MetricsDataSourceConfig.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/MetricsDataSourceConfig.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.studio.model;
-
+import lombok.Data;
import java.io.Serializable;
import java.util.Map;
@@ -29,6 +29,7 @@ import java.util.Map;
* password / bearerToken should be encrypted at rest in production.
* </p>
*/
+@Data
public class MetricsDataSourceConfig implements Serializable {
private static final long serialVersionUID = 1L;
@@ -89,94 +90,4 @@ public class MetricsDataSourceConfig implements Serializable {
* Whether this data source is currently activated.
*/
private boolean enabled;
-
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getAuthType() {
- return authType;
- }
-
- public void setAuthType(String authType) {
- this.authType = authType;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getBearerToken() {
- return bearerToken;
- }
-
- public void setBearerToken(String bearerToken) {
- this.bearerToken = bearerToken;
- }
-
- public String getProviderType() {
- return providerType;
- }
-
- public void setProviderType(String providerType) {
- this.providerType = providerType;
- }
-
- public boolean isTlsEnabled() {
- return tlsEnabled;
- }
-
- public void setTlsEnabled(boolean tlsEnabled) {
- this.tlsEnabled = tlsEnabled;
- }
-
- public Map<String, String> getDefaultLabels() {
- return defaultLabels;
- }
-
- public void setDefaultLabels(Map<String, String> defaultLabels) {
- this.defaultLabels = defaultLabels;
- }
-
- public int getScrapeInterval() {
- return scrapeInterval;
- }
-
- public void setScrapeInterval(int scrapeInterval) {
- this.scrapeInterval = scrapeInterval;
- }
-
- public boolean isEnabled() {
- return enabled;
- }
-
- public void setEnabled(boolean enabled) {
- this.enabled = enabled;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/MetricsHealthResult.java b/server/src/main/java/org/apache/rocketmq/studio/model/MetricsHealthResult.java
index 118ff31e..e94ae8da 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/MetricsHealthResult.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/MetricsHealthResult.java
@@ -16,7 +16,7 @@
*/
package org.apache.rocketmq.studio.model;
-
+import lombok.Data;
import java.io.Serializable;
import java.util.List;
@@ -24,6 +24,7 @@ import java.util.List;
* Result object returned by data-source health checks.
* Contains connection status, discovered metric families, and latency.
*/
+@Data
public class MetricsHealthResult implements Serializable {
private static final long serialVersionUID = 1L;
@@ -42,46 +43,4 @@ public class MetricsHealthResult implements Serializable {
/** Round-trip query latency in milliseconds during the health probe. */
private long queryLatencyMs;
-
-
- public boolean isConnected() {
- return connected;
- }
-
- public void setConnected(boolean connected) {
- this.connected = connected;
- }
-
- public String getStatusMessage() {
- return statusMessage;
- }
-
- public void setStatusMessage(String statusMessage) {
- this.statusMessage = statusMessage;
- }
-
- public List<String> getMissingMetricFamilies() {
- return missingMetricFamilies;
- }
-
- public void setMissingMetricFamilies(List<String> missingMetricFamilies) {
- this.missingMetricFamilies = missingMetricFamilies;
- }
-
- public List<String> getAvailableMetricFamilies() {
- return availableMetricFamilies;
- }
-
- public void setAvailableMetricFamilies(List<String> availableMetricFamilies) {
- this.availableMetricFamilies = availableMetricFamilies;
- }
-
- public long getQueryLatencyMs() {
- return queryLatencyMs;
- }
-
- public void setQueryLatencyMs(long queryLatencyMs) {
- this.queryLatencyMs = queryLatencyMs;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/Policy.java b/server/src/main/java/org/apache/rocketmq/studio/model/Policy.java
index 2483425e..216cf459 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/Policy.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/Policy.java
@@ -17,26 +17,11 @@
package org.apache.rocketmq.studio.model;
-
+import lombok.Data;
import java.util.List;
+@Data
public class Policy {
private String policyType;
private List<Entry> entries;
- public String getPolicyType() {
- return policyType;
- }
-
- public void setPolicyType(String policyType) {
- this.policyType = policyType;
- }
-
- public List<Entry> getEntries() {
- return entries;
- }
-
- public void setEntries(List<Entry> entries) {
- this.entries = entries;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/PolicyRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/PolicyRequest.java
index b143812e..d7000909 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/PolicyRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/PolicyRequest.java
@@ -17,44 +17,13 @@
package org.apache.rocketmq.studio.model;
-
+import lombok.Data;
import java.util.List;
+@Data
public class PolicyRequest {
private String clusterName;
private String brokerName;
private String subject;
private List<Policy> policies;
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public String getBrokerName() {
- return brokerName;
- }
-
- public void setBrokerName(String brokerName) {
- this.brokerName = brokerName;
- }
-
- public String getSubject() {
- return subject;
- }
-
- public void setSubject(String subject) {
- this.subject = subject;
- }
-
- public List<Policy> getPolicies() {
- return policies;
- }
-
- public void setPolicies(List<Policy> policies) {
- this.policies = policies;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/SubscriptionInfo.java b/server/src/main/java/org/apache/rocketmq/studio/model/SubscriptionInfo.java
index ccc3bd59..8e089f58 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/SubscriptionInfo.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/SubscriptionInfo.java
@@ -16,8 +16,10 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Map;
+@Data
public class SubscriptionInfo {
private String topic;
@@ -47,84 +49,4 @@ public class SubscriptionInfo {
public boolean isSQL92Subscription() {
return "SQL92".equals(subscriptionType);
}
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public String getConsumerGroup() {
- return consumerGroup;
- }
-
- public void setConsumerGroup(String consumerGroup) {
- this.consumerGroup = consumerGroup;
- }
-
- public String getSubExpression() {
- return subExpression;
- }
-
- public void setSubExpression(String subExpression) {
- this.subExpression = subExpression;
- }
-
- public String getSubscriptionType() {
- return subscriptionType;
- }
-
- public void setSubscriptionType(String subscriptionType) {
- this.subscriptionType = subscriptionType;
- }
-
- public Long getVersion() {
- return version;
- }
-
- public void setVersion(Long version) {
- this.version = version;
- }
-
- public Boolean getBroadcast() {
- return broadcast;
- }
-
- public void setBroadcast(Boolean broadcast) {
- this.broadcast = broadcast;
- }
-
- public String getConsumeFromWhere() {
- return consumeFromWhere;
- }
-
- public void setConsumeFromWhere(String consumeFromWhere) {
- this.consumeFromWhere = consumeFromWhere;
- }
-
- public Long getConsumeProgress() {
- return consumeProgress;
- }
-
- public void setConsumeProgress(Long consumeProgress) {
- this.consumeProgress = consumeProgress;
- }
-
- public Long getBacklogCount() {
- return backlogCount;
- }
-
- public void setBacklogCount(Long backlogCount) {
- this.backlogCount = backlogCount;
- }
-
- public Map<String, Object> getAttributes() {
- return attributes;
- }
-
- public void setAttributes(Map<String, Object> attributes) {
- this.attributes = attributes;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/TopicInfo.java b/server/src/main/java/org/apache/rocketmq/studio/model/TopicInfo.java
index bf5082cb..339b9eb2 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/TopicInfo.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/TopicInfo.java
@@ -16,9 +16,11 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
import java.util.Date;
import java.util.Map;
+@Data
public class TopicInfo {
private String topicName;
@@ -79,148 +81,4 @@ public class TopicInfo {
public boolean isTransactionTopic() {
return TopicType.TRANSACTION.equals(topicType);
}
- public String getTopicName() {
- return topicName;
- }
-
- public void setTopicName(String topicName) {
- this.topicName = topicName;
- }
-
- public TopicType getTopicType() {
- return topicType;
- }
-
- public void setTopicType(TopicType topicType) {
- this.topicType = topicType;
- }
-
- public Integer getReadQueueNums() {
- return readQueueNums;
- }
-
- public void setReadQueueNums(Integer readQueueNums) {
- this.readQueueNums = readQueueNums;
- }
-
- public Integer getWriteQueueNums() {
- return writeQueueNums;
- }
-
- public void setWriteQueueNums(Integer writeQueueNums) {
- this.writeQueueNums = writeQueueNums;
- }
-
- public Integer getPerm() {
- return perm;
- }
-
- public void setPerm(Integer perm) {
- this.perm = perm;
- }
-
- public Boolean getOrderTopic() {
- return orderTopic;
- }
-
- public void setOrderTopic(Boolean orderTopic) {
- this.orderTopic = orderTopic;
- }
-
- public Date getCreateTime() {
- return createTime;
- }
-
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
-
- public Date getUpdateTime() {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
-
- public String getTopicStatus() {
- return topicStatus;
- }
-
- public void setTopicStatus(String topicStatus) {
- this.topicStatus = topicStatus;
- }
-
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public Map<String, String> getAttributes() {
- return attributes;
- }
-
- public void setAttributes(Map<String, String> attributes) {
- this.attributes = attributes;
- }
-
- public Long getFifoTimeoutSeconds() {
- return fifoTimeoutSeconds;
- }
-
- public void setFifoTimeoutSeconds(Long fifoTimeoutSeconds) {
- this.fifoTimeoutSeconds = fifoTimeoutSeconds;
- }
-
- public Long getLiteTopicTTL() {
- return liteTopicTTL;
- }
-
- public void setLiteTopicTTL(Long liteTopicTTL) {
- this.liteTopicTTL = liteTopicTTL;
- }
-
- public String getSessionId() {
- return sessionId;
- }
-
- public void setSessionId(String sessionId) {
- this.sessionId = sessionId;
- }
-
- public String getAutoCreatePattern() {
- return autoCreatePattern;
- }
-
- public void setAutoCreatePattern(String autoCreatePattern) {
- this.autoCreatePattern = autoCreatePattern;
- }
-
- public String getDelayLevel() {
- return delayLevel;
- }
-
- public void setDelayLevel(String delayLevel) {
- this.delayLevel = delayLevel;
- }
-
- public String getTransactionServerAddr() {
- return transactionServerAddr;
- }
-
- public void setTransactionServerAddr(String transactionServerAddr) {
- this.transactionServerAddr = transactionServerAddr;
- }
-
- public Long getTransactionTimeoutSeconds() {
- return transactionTimeoutSeconds;
- }
-
- public void setTransactionTimeoutSeconds(Long transactionTimeoutSeconds) {
- this.transactionTimeoutSeconds = transactionTimeoutSeconds;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/User.java b/server/src/main/java/org/apache/rocketmq/studio/model/User.java
index 6844d093..4f1772b3 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/User.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/User.java
@@ -17,18 +17,21 @@
package org.apache.rocketmq.studio.model;
import org.hibernate.validator.constraints.Range;
+import lombok.Data;
+import lombok.ToString;
+@Data
public class User {
public static final int SUPER = 0;
public static final int NORMAL = 1;
private long id;
private String name;
+ @ToString.Exclude
private String password;
@Range(min = 0, max = 1)
private int type = 0;
-
public User(String name, String password, int type) {
this.name = name;
this.password = password;
@@ -38,46 +41,4 @@ public class User {
public User cloneOne() {
return new User(this.name, this.password, this.type);
}
-
- public long getId() {
- return id;
- }
-
- public void setId(long id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public int getType() {
- return type;
- }
-
- public void setType(int type) {
- this.type = type;
- }
-
- @Override
- public String toString() {
- return "User{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", password='******'" +
- ", type=" + type +
- '}';
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/UserInfo.java b/server/src/main/java/org/apache/rocketmq/studio/model/UserInfo.java
index b5f21236..87d55bd9 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/UserInfo.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/UserInfo.java
@@ -16,52 +16,13 @@
*/
package org.apache.rocketmq.studio.model;
+import lombok.Data;
+
+@Data
public class UserInfo {
public static final String USER_INFO = "userInfo";
private User user;
private long loginTime;
private String ip;
private String sessionId;
-
- public long getLoginTime() {
- return loginTime;
- }
-
- public void setLoginTime(long loginTime) {
- this.loginTime = loginTime;
- }
-
- public String getIp() {
- return ip;
- }
-
- public void setIp(String ip) {
- this.ip = ip;
- }
-
- public User getUser() {
- return user;
- }
-
- public void setUser(User user) {
- this.user = user;
- }
-
- public String getSessionId() {
- return sessionId;
- }
-
- public void setSessionId(String sessionId) {
- this.sessionId = sessionId;
- }
-
- @Override
- public String toString() {
- return "UserInfo{" +
- "user=" + user +
- ", loginTime=" + loginTime +
- ", ip='" + ip + '\'' +
- ", sessionId='" + sessionId + '\'' +
- '}';
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/ArchitectureSwitchRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/ArchitectureSwitchRequest.java
index 574eb099..f996ee04 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/ArchitectureSwitchRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/ArchitectureSwitchRequest.java
@@ -16,6 +16,8 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+
/**
* Request body for architecture switch operation.
*
@@ -26,6 +28,7 @@ package org.apache.rocketmq.studio.model.request;
* {@code proxyAddresses} and {@code nameSrvAddress} fields are required.
* For V4 architecture, only {@code accessType} is needed.</p>
*/
+@Data
public class ArchitectureSwitchRequest {
/**
@@ -45,28 +48,4 @@ public class ArchitectureSwitchRequest {
* Required when accessType is V5_PROXY_LOCAL or V5_PROXY_CLUSTER.
*/
private String nameSrvAddress;
-
- public String getAccessType() {
- return accessType;
- }
-
- public void setAccessType(String accessType) {
- this.accessType = accessType;
- }
-
- public String[] getProxyAddresses() {
- return proxyAddresses;
- }
-
- public void setProxyAddresses(String[] proxyAddresses) {
- this.proxyAddresses = proxyAddresses;
- }
-
- public String getNameSrvAddress() {
- return nameSrvAddress;
- }
-
- public void setNameSrvAddress(String nameSrvAddress) {
- this.nameSrvAddress = nameSrvAddress;
- }
-}
\ No newline at end of file
+}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/MessageQuery.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/MessageQuery.java
index 141ce421..57d6a78a 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/MessageQuery.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/MessageQuery.java
@@ -16,6 +16,9 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+
+@Data
public class MessageQuery {
/**
* current page num
@@ -31,52 +34,4 @@ public class MessageQuery {
private long begin;
private long end;
-
- public int getPageNum() {
- return pageNum;
- }
-
- public void setPageNum(int pageNum) {
- this.pageNum = pageNum;
- }
-
- public int getPageSize() {
- return pageSize;
- }
-
- public void setPageSize(int pageSize) {
- this.pageSize = pageSize;
- }
-
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public String getTaskId() {
- return taskId;
- }
-
- public void setTaskId(String taskId) {
- this.taskId = taskId;
- }
-
- public long getBegin() {
- return begin;
- }
-
- public void setBegin(long begin) {
- this.begin = begin;
- }
-
- public long getEnd() {
- return end;
- }
-
- public void setEnd(long end) {
- this.end = end;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceQueryRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceQueryRequest.java
index 7144f193..5c4468a0 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceQueryRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceQueryRequest.java
@@ -17,6 +17,7 @@
package org.apache.rocketmq.studio.model.request;
import org.apache.rocketmq.studio.cluster.metrics.MetricQueryDTO;
+import lombok.Data;
/**
* Request to run a PromQL range query against a configured data source.
@@ -26,6 +27,7 @@ import org.apache.rocketmq.studio.cluster.metrics.MetricQueryDTO;
* never persisted, mirroring the existing {@code /api/settings/datasources/test}
* flow.</p>
*/
+@Data
public class MetricsDataSourceQueryRequest {
private MetricQueryDTO query;
@@ -35,36 +37,4 @@ public class MetricsDataSourceQueryRequest {
private String password;
private String bearerToken;
-
- public MetricQueryDTO getQuery() {
- return query;
- }
-
- public void setQuery(MetricQueryDTO query) {
- this.query = query;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getBearerToken() {
- return bearerToken;
- }
-
- public void setBearerToken(String bearerToken) {
- this.bearerToken = bearerToken;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceRequest.java
index 72846b2b..6e2483f2 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/MetricsDataSourceRequest.java
@@ -16,6 +16,7 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
/**
* Metrics data source configuration request DTO.
@@ -31,6 +32,7 @@ package org.apache.rocketmq.studio.model.request;
* <li><b>CORTEX:</b> Cortex (Prometheus-compatible)</li>
* </ul>
*/
+@Data
public class MetricsDataSourceRequest {
/**
@@ -104,108 +106,4 @@ public class MetricsDataSourceRequest {
* Additional description or notes about this data source.
*/
private String description;
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getType() {
- return type;
- }
-
- public void setType(String type) {
- this.type = type;
- }
-
- public String getProviderType() {
- return providerType;
- }
-
- public void setProviderType(String providerType) {
- this.providerType = providerType;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getBearerToken() {
- return bearerToken;
- }
-
- public void setBearerToken(String bearerToken) {
- this.bearerToken = bearerToken;
- }
-
- public boolean isIsDefault() {
- return isDefault;
- }
-
- public void setIsDefault(boolean isDefault) {
- this.isDefault = isDefault;
- }
-
- public boolean isReadOnly() {
- return readOnly;
- }
-
- public void setReadOnly(boolean readOnly) {
- this.readOnly = readOnly;
- }
-
- public String getCustomHeaders() {
- return customHeaders;
- }
-
- public void setCustomHeaders(String customHeaders) {
- this.customHeaders = customHeaders;
- }
-
- public Integer getConnectionTimeoutMs() {
- return connectionTimeoutMs;
- }
-
- public void setConnectionTimeoutMs(Integer connectionTimeoutMs) {
- this.connectionTimeoutMs = connectionTimeoutMs;
- }
-
- public Integer getReadTimeoutMs() {
- return readTimeoutMs;
- }
-
- public void setReadTimeoutMs(Integer readTimeoutMs) {
- this.readTimeoutMs = readTimeoutMs;
- }
-
- public String getDescription() {
- return description;
- }
-
- public void setDescription(String description) {
- this.description = description;
- }
-
}
\ No newline at end of file
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/ResetOffsetRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/ResetOffsetRequest.java
index f741dd3f..9c8a2bf9 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/ResetOffsetRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/ResetOffsetRequest.java
@@ -16,43 +16,13 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
import java.util.List;
+@Data
public class ResetOffsetRequest {
private List<String> consumerGroupList;
private String topic;
private long resetTime;
private boolean force;
-
- public List<String> getConsumerGroupList() {
- return consumerGroupList;
- }
-
- public void setConsumerGroupList(List<String> consumerGroupList) {
- this.consumerGroupList = consumerGroupList;
- }
-
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public long getResetTime() {
- return resetTime;
- }
-
- public void setResetTime(long resetTime) {
- this.resetTime = resetTime;
- }
-
- public boolean isForce() {
- return force;
- }
-
- public void setForce(boolean force) {
- this.force = force;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/SendTopicMessageRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/SendTopicMessageRequest.java
index 624b739e..ec7a139a 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/SendTopicMessageRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/SendTopicMessageRequest.java
@@ -16,51 +16,13 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+@Data
public class SendTopicMessageRequest {
private String topic;
private String key;
private String tag;
private String messageBody;
private boolean traceEnabled;
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public String getTag() {
- return tag;
- }
-
- public void setTag(String tag) {
- this.tag = tag;
- }
-
- public String getMessageBody() {
- return messageBody;
- }
-
- public void setMessageBody(String messageBody) {
- this.messageBody = messageBody;
- }
-
- public boolean isTraceEnabled() {
- return traceEnabled;
- }
-
- public void setTraceEnabled(boolean traceEnabled) {
- this.traceEnabled = traceEnabled;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeList.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeList.java
index ec059079..2ce80fd9 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeList.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeList.java
@@ -16,28 +16,14 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
import java.util.List;
+@Data
public class TopicTypeList {
private List<String> topicNameList;
private List<String> messageTypeList;
- public List<String> getTopicNameList() {
- return topicNameList;
- }
-
- public void setTopicNameList(List<String> topicNameList) {
- this.topicNameList = topicNameList;
- }
-
- public List<String> getMessageTypeList() {
- return messageTypeList;
- }
-
- public void setMessageTypeList(List<String> messageTypeList) {
- this.messageTypeList = messageTypeList;
- }
-
public TopicTypeList(List<String> topicNameList, List<String> messageTypeList) {
this.topicNameList = topicNameList;
this.messageTypeList = messageTypeList;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeMeta.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeMeta.java
index 22148962..99660d6a 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeMeta.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/TopicTypeMeta.java
@@ -16,23 +16,10 @@
*/
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+
+@Data
public class TopicTypeMeta {
private String topicName;
private String messageType;
-
- public String getTopicName() {
- return topicName;
- }
-
- public void setTopicName(String topicName) {
- this.topicName = topicName;
- }
-
- public String getMessageType() {
- return messageType;
- }
-
- public void setMessageType(String messageType) {
- this.messageType = messageType;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/UserCreateRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/UserCreateRequest.java
index 20a76d53..758e11d9 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/UserCreateRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/UserCreateRequest.java
@@ -17,33 +17,11 @@
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+@Data
public class UserCreateRequest {
private String clusterName;
private String brokerName;
private UserInfoParam userInfo;
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public String getBrokerName() {
- return brokerName;
- }
-
- public void setBrokerName(String brokerName) {
- this.brokerName = brokerName;
- }
-
- public UserInfoParam getUserInfo() {
- return userInfo;
- }
-
- public void setUserInfo(UserInfoParam userInfo) {
- this.userInfo = userInfo;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/UserInfoParam.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/UserInfoParam.java
index f733edbd..0037a545 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/UserInfoParam.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/UserInfoParam.java
@@ -17,42 +17,12 @@
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+@Data
public class UserInfoParam {
private String username;
private String password;
private String userStatus;
private String userType;
- public String getUsername() {
- return username;
- }
-
- public void setUsername(String username) {
- this.username = username;
- }
-
- public String getPassword() {
- return password;
- }
-
- public void setPassword(String password) {
- this.password = password;
- }
-
- public String getUserStatus() {
- return userStatus;
- }
-
- public void setUserStatus(String userStatus) {
- this.userStatus = userStatus;
- }
-
- public String getUserType() {
- return userType;
- }
-
- public void setUserType(String userType) {
- this.userType = userType;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/request/UserUpdateRequest.java b/server/src/main/java/org/apache/rocketmq/studio/model/request/UserUpdateRequest.java
index 65e8596d..1027a25b 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/request/UserUpdateRequest.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/request/UserUpdateRequest.java
@@ -17,33 +17,11 @@
package org.apache.rocketmq.studio.model.request;
+import lombok.Data;
+@Data
public class UserUpdateRequest {
private String clusterName;
private String brokerName;
private UserInfoParam userInfo;
- public String getClusterName() {
- return clusterName;
- }
-
- public void setClusterName(String clusterName) {
- this.clusterName = clusterName;
- }
-
- public String getBrokerName() {
- return brokerName;
- }
-
- public void setBrokerName(String brokerName) {
- this.brokerName = brokerName;
- }
-
- public UserInfoParam getUserInfo() {
- return userInfo;
- }
-
- public void setUserInfo(UserInfoParam userInfo) {
- this.userInfo = userInfo;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/trace/MessageTraceGraph.java b/server/src/main/java/org/apache/rocketmq/studio/model/trace/MessageTraceGraph.java
index f1a0abcb..6b518aaa 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/trace/MessageTraceGraph.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/trace/MessageTraceGraph.java
@@ -17,36 +17,12 @@
package org.apache.rocketmq.studio.model.trace;
-
+import lombok.Data;
import java.util.List;
+@Data
public class MessageTraceGraph {
private ProducerNode producerNode;
private List<SubscriptionNode> subscriptionNodeList;
private List<Object> messageTraceViews;
-
- public ProducerNode getProducerNode() {
- return producerNode;
- }
-
- public void setProducerNode(ProducerNode producerNode) {
- this.producerNode = producerNode;
- }
-
- public List<SubscriptionNode> getSubscriptionNodeList() {
- return subscriptionNodeList;
- }
-
- public void setSubscriptionNodeList(List<SubscriptionNode> subscriptionNodeList) {
- this.subscriptionNodeList = subscriptionNodeList;
- }
-
- public List<Object> getMessageTraceViews() {
- return messageTraceViews;
- }
-
- public void setMessageTraceViews(List<Object> messageTraceViews) {
- this.messageTraceViews = messageTraceViews;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/trace/ProducerNode.java b/server/src/main/java/org/apache/rocketmq/studio/model/trace/ProducerNode.java
index a3c40225..43f78338 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/trace/ProducerNode.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/trace/ProducerNode.java
@@ -16,9 +16,10 @@
*/
package org.apache.rocketmq.studio.model.trace;
-
+import lombok.Data;
import java.util.List;
+@Data
public class ProducerNode {
private String msgId;
private String tags;
@@ -28,68 +29,4 @@ public class ProducerNode {
private String groupName;
private TraceNode traceNode;
private List<TraceNode> transactionNodeList;
- public String getMsgId() {
- return msgId;
- }
-
- public void setMsgId(String msgId) {
- this.msgId = msgId;
- }
-
- public String getTags() {
- return tags;
- }
-
- public void setTags(String tags) {
- this.tags = tags;
- }
-
- public String getKeys() {
- return keys;
- }
-
- public void setKeys(String keys) {
- this.keys = keys;
- }
-
- public String getOffSetMsgId() {
- return offSetMsgId;
- }
-
- public void setOffSetMsgId(String offSetMsgId) {
- this.offSetMsgId = offSetMsgId;
- }
-
- public String getTopic() {
- return topic;
- }
-
- public void setTopic(String topic) {
- this.topic = topic;
- }
-
- public String getGroupName() {
- return groupName;
- }
-
- public void setGroupName(String groupName) {
- this.groupName = groupName;
- }
-
- public TraceNode getTraceNode() {
- return traceNode;
- }
-
- public void setTraceNode(TraceNode traceNode) {
- this.traceNode = traceNode;
- }
-
- public List<TraceNode> getTransactionNodeList() {
- return transactionNodeList;
- }
-
- public void setTransactionNodeList(List<TraceNode> transactionNodeList) {
- this.transactionNodeList = transactionNodeList;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/trace/SubscriptionNode.java b/server/src/main/java/org/apache/rocketmq/studio/model/trace/SubscriptionNode.java
index b0239a7f..e6bd72d6 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/trace/SubscriptionNode.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/trace/SubscriptionNode.java
@@ -16,26 +16,11 @@
*/
package org.apache.rocketmq.studio.model.trace;
-
+import lombok.Data;
import java.util.List;
+@Data
public class SubscriptionNode {
private String subscriptionGroup;
private List<TraceNode> consumeNodeList;
- public String getSubscriptionGroup() {
- return subscriptionGroup;
- }
-
- public void setSubscriptionGroup(String subscriptionGroup) {
- this.subscriptionGroup = subscriptionGroup;
- }
-
- public List<TraceNode> getConsumeNodeList() {
- return consumeNodeList;
- }
-
- public void setConsumeNodeList(List<TraceNode> consumeNodeList) {
- this.consumeNodeList = consumeNodeList;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/model/trace/TraceNode.java b/server/src/main/java/org/apache/rocketmq/studio/model/trace/TraceNode.java
index 921364ea..910c6cef 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/model/trace/TraceNode.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/model/trace/TraceNode.java
@@ -17,7 +17,9 @@
package org.apache.rocketmq.studio.model.trace;
+import lombok.Data;
+@Data
public class TraceNode {
private String requestId;
private String storeHost;
@@ -31,100 +33,4 @@ public class TraceNode {
private String transactionId;
private boolean fromTransactionCheck;
private String msgType;
- public String getRequestId() {
- return requestId;
- }
-
- public void setRequestId(String requestId) {
- this.requestId = requestId;
- }
-
- public String getStoreHost() {
- return storeHost;
- }
-
- public void setStoreHost(String storeHost) {
- this.storeHost = storeHost;
- }
-
- public String getClientHost() {
- return clientHost;
- }
-
- public void setClientHost(String clientHost) {
- this.clientHost = clientHost;
- }
-
- public int getCostTime() {
- return costTime;
- }
-
- public void setCostTime(int costTime) {
- this.costTime = costTime;
- }
-
- public long getBeginTimestamp() {
- return beginTimestamp;
- }
-
- public void setBeginTimestamp(long beginTimestamp) {
- this.beginTimestamp = beginTimestamp;
- }
-
- public long getEndTimestamp() {
- return endTimestamp;
- }
-
- public void setEndTimestamp(long endTimestamp) {
- this.endTimestamp = endTimestamp;
- }
-
- public int getRetryTimes() {
- return retryTimes;
- }
-
- public void setRetryTimes(int retryTimes) {
- this.retryTimes = retryTimes;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getTransactionState() {
- return transactionState;
- }
-
- public void setTransactionState(String transactionState) {
- this.transactionState = transactionState;
- }
-
- public String getTransactionId() {
- return transactionId;
- }
-
- public void setTransactionId(String transactionId) {
- this.transactionId = transactionId;
- }
-
- public boolean isFromTransactionCheck() {
- return fromTransactionCheck;
- }
-
- public void setFromTransactionCheck(boolean fromTransactionCheck) {
- this.fromTransactionCheck = fromTransactionCheck;
- }
-
- public String getMsgType() {
- return msgType;
- }
-
- public void setMsgType(String msgType) {
- this.msgType = msgType;
- }
-
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigDTO.java b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigDTO.java
new file mode 100644
index 00000000..d2220e6e
--- /dev/null
+++ b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigDTO.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.rocketmq.studio.ops.ai;
+
+import lombok.Data;
+
+@Data
+public class LlmConfigDTO {
+
+ private String provider;
+ private String engine;
+ private String apiKey;
+ private String apiBase;
+ private String model;
+ private int maxTokens;
+ private double temperature;
+ private boolean enabled;
+ private String deploymentName;
+ private String apiVersion;
+ private String awsRegion;
+
+ public LlmConfigVO toLlmConfigVO() {
+ return LlmConfigVO.builder()
+ .provider(provider)
+ .engine(engine)
+ .apiKey(apiKey)
+ .apiBase(apiBase)
+ .model(model)
+ .maxTokens(maxTokens)
+ .temperature(temperature)
+ .enabled(enabled)
+ .deploymentName(deploymentName)
+ .apiVersion(apiVersion)
+ .awsRegion(awsRegion)
+ .build();
+ }
+}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
index 75be1dbc..fe7543a5 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
@@ -17,6 +17,8 @@
package org.apache.rocketmq.studio.ops.ai;
+import org.springframework.util.StringUtils;
+
import org.apache.rocketmq.studio.settings.GeneralSettingsVO;
import org.apache.rocketmq.studio.settings.SettingsService;
import lombok.RequiredArgsConstructor;
@@ -80,7 +82,7 @@ public class LlmConfigService {
? copy(overrides)
: fromGeneralSettings(settingsService.getGeneralSettings());
String token = envToken();
- if (!isBlank(token)) {
+ if (!!StringUtils.hasText(token)) {
config.setApiKey(token.trim());
config.setEnabled(true);
}
@@ -95,7 +97,7 @@ public class LlmConfigService {
}
GeneralSettingsVO current = settingsService.getGeneralSettings();
// The env-injected token is authoritative at runtime but must never be persisted.
- String persistedApiKey = isBlank(envToken())
+ String persistedApiKey = !StringUtils.hasText(envToken())
? normalized.getApiKey()
: defaultString(current.getApiKey(), "");
GeneralSettingsVO updated = GeneralSettingsVO.builder()
@@ -155,19 +157,19 @@ public class LlmConfigService {
}
boolean keyRequired = !"ollama".equals(provider)
&& LlmConfigVO.ENGINE_HTTP.equalsIgnoreCase(normalized.normalizeEngine());
- if (keyRequired && isBlank(normalized.getApiKey())) {
+ if (keyRequired && !StringUtils.hasText(normalized.getApiKey())) {
return LlmOperationResultVO.failure(
"llm.config.missing_api_key",
"LLM API key is required",
"Configure an API key for provider " + provider + ", or select ollama for a local provider.");
}
- if ("azure".equals(provider) && isBlank(normalized.getDeploymentName())) {
+ if ("azure".equals(provider) && !StringUtils.hasText(normalized.getDeploymentName())) {
return LlmOperationResultVO.failure(
"llm.config.missing_deployment",
"Azure OpenAI deployment name is required",
"Set the Azure deployment name that maps to the selected model.");
}
- if (isBlank(normalized.getModel())) {
+ if (!StringUtils.hasText(normalized.getModel())) {
return LlmOperationResultVO.failure(
"llm.config.missing_model",
"LLM model is required",
@@ -215,7 +217,7 @@ public class LlmConfigService {
.model(model)
.maxTokens(DEFAULT_MAX_TOKENS)
.temperature(DEFAULT_TEMPERATURE)
- .enabled(!requiresApiKey(provider) || !isBlank(apiKey))
+ .enabled(!requiresApiKey(provider) || !!StringUtils.hasText(apiKey))
.apiVersion("2024-02-15-preview")
.awsRegion("us-east-1")
.build();
@@ -253,11 +255,11 @@ public class LlmConfigService {
normalized.setApiKey("");
return normalized;
}
- if (isBlank(normalized.getApiKey())) {
+ if (!StringUtils.hasText(normalized.getApiKey())) {
// Fall back to the key stored in settings only; the env-injected token
// must never be persisted into the settings table.
String storedKey = settingsService.getGeneralSettings().getApiKey();
- if (!isBlank(envToken())) {
+ if (!!StringUtils.hasText(envToken())) {
storedKey = defaultString(storedKey, envToken());
}
normalized.setApiKey(defaultString(storedKey, ""));
@@ -319,7 +321,7 @@ public class LlmConfigService {
try {
URI uri = new URI(apiBase);
String scheme = uri.getScheme() == null ? "" : uri.getScheme().toLowerCase(Locale.ROOT);
- return ("http".equals(scheme) || "https".equals(scheme)) && !isBlank(uri.getHost())
+ return ("http".equals(scheme) || "https".equals(scheme)) && !!StringUtils.hasText(uri.getHost())
&& !apiBase.endsWith(CHAT_COMPLETIONS_PATH);
} catch (URISyntaxException exception) {
return false;
@@ -327,10 +329,7 @@ public class LlmConfigService {
}
private String defaultString(String value, String fallback) {
- return isBlank(value) ? fallback : value.trim();
+ return !StringUtils.hasText(value) ? fallback : value.trim();
}
- private boolean isBlank(String value) {
- return value == null || value.trim().isEmpty();
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmController.java b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmController.java
index 1c493c70..3410c813 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmController.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmController.java
@@ -18,6 +18,7 @@
package org.apache.rocketmq.studio.ops.ai;
import lombok.RequiredArgsConstructor;
+import org.apache.rocketmq.studio.common.domain.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -32,23 +33,23 @@ public class LlmController {
private final LlmConfigService llmConfigService;
@GetMapping("/config")
- public LlmConfigVO getConfig() {
- return llmConfigService.getConfig();
+ public Result<LlmConfigVO> getConfig() {
+ return Result.ok(llmConfigService.getConfig());
}
@PostMapping("/config")
- public LlmOperationResultVO saveConfig(@RequestBody LlmConfigVO config) {
- llmConfigService.saveConfig(config);
- return LlmOperationResultVO.success("saved");
+ public Result<LlmOperationResultVO> saveConfig(@RequestBody LlmConfigDTO config) {
+ llmConfigService.saveConfig(config.toLlmConfigVO());
+ return Result.ok(LlmOperationResultVO.success("saved"));
}
@PostMapping("/config/test")
- public LlmOperationResultVO testConfig(@RequestBody LlmConfigVO config) {
- return llmConfigService.testConfig(config);
+ public Result<LlmOperationResultVO> testConfig(@RequestBody LlmConfigDTO config) {
+ return Result.ok(llmConfigService.testConfig(config.toLlmConfigVO()));
}
@GetMapping("/models")
- public LlmModelsResultVO listModels() {
- return llmConfigService.listModels();
+ public Result<LlmModelsResultVO> listModels() {
+ return Result.ok(llmConfigService.listModels());
}
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/ToolCatalog.java b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/ToolCatalog.java
index 4f738c7d..d33d2a49 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/ToolCatalog.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/tool/ToolCatalog.java
@@ -23,6 +23,7 @@ import com.networknt.schema.InputFormat;
import com.networknt.schema.Schema;
import com.networknt.schema.SchemaRegistry;
import com.networknt.schema.SpecificationVersion;
+import lombok.Getter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -49,8 +50,11 @@ public class ToolCatalog {
private static final String CLUSTER_LIST_TOOL = "rmq.cluster.list";
private static final ObjectMapper YAML_MAPPER = new ObjectMapper(new YAMLFactory());
+ @Getter
private final String version;
+ @Getter
private final String minimumClientVersion;
+ @Getter
private final String digest;
private final List<ToolDefinition> definitions;
private final Map<String, ToolDefinition> definitionsByName;
@@ -155,18 +159,6 @@ public class ToolCatalog {
}
}
- public String getVersion() {
- return version;
- }
-
- public String getMinimumClientVersion() {
- return minimumClientVersion;
- }
-
- public String getDigest() {
- return digest;
- }
-
public List<ToolDefinition> list() {
return definitions;
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java
index b3aca288..27f31393 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/ops/alert/MybatisPlusAlertRepository.java
@@ -24,6 +24,7 @@ import org.apache.rocketmq.studio.persistence.mapper.RmqAlertRuleMapper;
import org.apache.rocketmq.studio.persistence.mapper.RmqSystemAlertMapper;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
import java.time.LocalDateTime;
import java.util.Arrays;
@@ -33,17 +34,13 @@ import java.util.stream.Collectors;
/**
* MySQL-backed alert repository for alert rules and system alert events.
*/
+@RequiredArgsConstructor
@Repository
public class MybatisPlusAlertRepository implements AlertRepository {
private final RmqAlertRuleMapper ruleMapper;
private final RmqSystemAlertMapper alertMapper;
- public MybatisPlusAlertRepository(RmqAlertRuleMapper ruleMapper, RmqSystemAlertMapper alertMapper) {
- this.ruleMapper = ruleMapper;
- this.alertMapper = alertMapper;
- }
-
@Override
public List<AlertRuleVO> findAllRules() {
return ruleMapper.selectList(new QueryWrapper<RmqAlertRule>().orderByAsc("name")).stream()
diff --git a/server/src/main/java/org/apache/rocketmq/studio/ops/audit/MybatisPlusAuditRepository.java b/server/src/main/java/org/apache/rocketmq/studio/ops/audit/MybatisPlusAuditRepository.java
index 9d2f2451..acdb9015 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/ops/audit/MybatisPlusAuditRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/ops/audit/MybatisPlusAuditRepository.java
@@ -23,21 +23,19 @@ import org.apache.rocketmq.studio.persistence.entity.RmqOperationAudit;
import org.apache.rocketmq.studio.persistence.mapper.RmqOperationAuditMapper;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
/** MySQL-backed audit repository (rmq_operation_audit). */
+@RequiredArgsConstructor
@Repository
public class MybatisPlusAuditRepository implements AuditRepository {
private final RmqOperationAuditMapper auditMapper;
- public MybatisPlusAuditRepository(RmqOperationAuditMapper auditMapper) {
- this.auditMapper = auditMapper;
- }
-
@Override
public PageResult<AuditRecordVO> findPage(String search, String operationType,
LocalDateTime startDate, LocalDateTime endDate,
diff --git a/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqCloudCredential.java b/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqCloudCredential.java
index 155e79f5..4aca2975 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqCloudCredential.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/persistence/entity/RmqCloudCredential.java
@@ -19,9 +19,11 @@ package org.apache.rocketmq.studio.persistence.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
import java.time.LocalDateTime;
+@Data
@TableName("rmq_cloud_credential")
public class RmqCloudCredential {
@@ -41,68 +43,4 @@ public class RmqCloudCredential {
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getVendor() {
- return vendor;
- }
-
- public void setVendor(String vendor) {
- this.vendor = vendor;
- }
-
- public String getAccessKey() {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey) {
- this.accessKey = accessKey;
- }
-
- public String getSecretKey() {
- return secretKey;
- }
-
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
-
- public String getRemark() {
- return remark;
- }
-
- public void setRemark(String remark) {
- this.remark = remark;
- }
-
- public LocalDateTime getCreatedAt() {
- return createdAt;
- }
-
- public void setCreatedAt(LocalDateTime createdAt) {
- this.createdAt = createdAt;
- }
-
- public LocalDateTime getUpdatedAt() {
- return updatedAt;
- }
-
- public void setUpdatedAt(LocalDateTime updatedAt) {
- this.updatedAt = updatedAt;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceDetailVO.java b/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceDetailVO.java
index ef736b36..928e4143 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceDetailVO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceDetailVO.java
@@ -16,8 +16,12 @@
*/
package org.apache.rocketmq.studio.provider;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import java.util.List;
+@Data
public class CloudInstanceDetailVO {
private String instanceId;
@@ -27,80 +31,11 @@ public class CloudInstanceDetailVO {
private String remark;
private List<CloudEndpoint> endpoints;
- public String getInstanceId() {
- return instanceId;
- }
-
- public void setInstanceId(String instanceId) {
- this.instanceId = instanceId;
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- public void setInstanceName(String instanceName) {
- this.instanceName = instanceName;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getRegionId() {
- return regionId;
- }
-
- public void setRegionId(String regionId) {
- this.regionId = regionId;
- }
-
- public String getRemark() {
- return remark;
- }
-
- public void setRemark(String remark) {
- this.remark = remark;
- }
-
- public List<CloudEndpoint> getEndpoints() {
- return endpoints;
- }
-
- public void setEndpoints(List<CloudEndpoint> endpoints) {
- this.endpoints = endpoints;
- }
-
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
public static class CloudEndpoint {
private String endpointType;
private String endpointUrl;
-
- public CloudEndpoint() {
- }
-
- public CloudEndpoint(String endpointType, String endpointUrl) {
- this.endpointType = endpointType;
- this.endpointUrl = endpointUrl;
- }
-
- public String getEndpointType() {
- return endpointType;
- }
-
- public void setEndpointType(String endpointType) {
- this.endpointType = endpointType;
- }
-
- public String getEndpointUrl() {
- return endpointUrl;
- }
-
- public void setEndpointUrl(String endpointUrl) {
- this.endpointUrl = endpointUrl;
- }
}
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceOptionVO.java b/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceOptionVO.java
index e3d1da28..67d5c933 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceOptionVO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/CloudInstanceOptionVO.java
@@ -16,6 +16,9 @@
*/
package org.apache.rocketmq.studio.provider;
+import lombok.Data;
+
+@Data
public class CloudInstanceOptionVO {
private String instanceId;
@@ -25,60 +28,4 @@ public class CloudInstanceOptionVO {
private Integer topicCount;
private Integer groupCount;
private String remark;
-
- public String getInstanceId() {
- return instanceId;
- }
-
- public void setInstanceId(String instanceId) {
- this.instanceId = instanceId;
- }
-
- public String getInstanceName() {
- return instanceName;
- }
-
- public void setInstanceName(String instanceName) {
- this.instanceName = instanceName;
- }
-
- public String getStatus() {
- return status;
- }
-
- public void setStatus(String status) {
- this.status = status;
- }
-
- public String getRegionId() {
- return regionId;
- }
-
- public void setRegionId(String regionId) {
- this.regionId = regionId;
- }
-
- public Integer getTopicCount() {
- return topicCount;
- }
-
- public void setTopicCount(Integer topicCount) {
- this.topicCount = topicCount;
- }
-
- public Integer getGroupCount() {
- return groupCount;
- }
-
- public void setGroupCount(Integer groupCount) {
- this.groupCount = groupCount;
- }
-
- public String getRemark() {
- return remark;
- }
-
- public void setRemark(String remark) {
- this.remark = remark;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/CloudRegionVO.java b/server/src/main/java/org/apache/rocketmq/studio/provider/CloudRegionVO.java
index 2a068a4b..7ff7b966 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/CloudRegionVO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/CloudRegionVO.java
@@ -16,32 +16,15 @@
*/
package org.apache.rocketmq.studio.provider;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
public class CloudRegionVO {
private String regionId;
private String regionName;
-
- public CloudRegionVO() {
- }
-
- public CloudRegionVO(String regionId, String regionName) {
- this.regionId = regionId;
- this.regionName = regionName;
- }
-
- public String getRegionId() {
- return regionId;
- }
-
- public void setRegionId(String regionId) {
- this.regionId = regionId;
- }
-
- public String getRegionName() {
- return regionName;
- }
-
- public void setRegionName(String regionName) {
- this.regionName = regionName;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProvider.java
index 65a9a945..e3f2fa19 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/InstanceProvider.java
@@ -36,6 +36,10 @@ public interface InstanceProvider {
InstanceVendor vendor();
+ int countTopics(String instanceId);
+
+ int countGroups(String instanceId);
+
List<TopicVO> listTopics(String instanceId, String type, String search);
TopicVO createTopic(String instanceId, TopicVO topic);
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogController.java b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogController.java
index 25828c94..4fbc8c64 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogController.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogController.java
@@ -23,22 +23,20 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
+import lombok.RequiredArgsConstructor;
import java.util.List;
/**
* REST endpoints for browsing the Aliyun cloud catalog with a stored credential.
*/
+@RequiredArgsConstructor
@RestController
@RequestMapping("/api/cloud/aliyun")
public class AliyunCatalogController {
private final AliyunCatalogService catalogService;
- public AliyunCatalogController(AliyunCatalogService catalogService) {
- this.catalogService = catalogService;
- }
-
@GetMapping("/regions")
public Result<List<CloudRegionVO>> listRegions(@RequestParam String credentialId) {
return Result.ok(catalogService.listRegions(credentialId));
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogService.java b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogService.java
index cb1d6311..1e6ce14b 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunCatalogService.java
@@ -32,6 +32,7 @@ import org.apache.rocketmq.studio.provider.CloudInstanceDetailVO;
import org.apache.rocketmq.studio.provider.CloudInstanceOptionVO;
import org.apache.rocketmq.studio.provider.CloudRegionVO;
import org.springframework.stereotype.Component;
+import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.Comparator;
@@ -41,6 +42,7 @@ import java.util.Locale;
/**
* Aliyun cloud catalog: regions and commercial RocketMQ 5.x instances visible to a credential.
*/
+@RequiredArgsConstructor
@Component
public class AliyunCatalogService implements CloudCatalogProvider {
@@ -51,10 +53,6 @@ public class AliyunCatalogService implements CloudCatalogProvider {
private final AliyunClientFactory clientFactory;
- public AliyunCatalogService(AliyunClientFactory clientFactory) {
- this.clientFactory = clientFactory;
- }
-
@Override
public InstanceVendor vendor() {
return InstanceVendor.ALIYUN;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactory.java b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactory.java
index 214a56a8..bac4f3d7 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactory.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactory.java
@@ -25,12 +25,12 @@ import darabonba.core.client.ClientOverrideConfiguration;
import darabonba.core.exception.ClientException;
import darabonba.core.exception.ServerException;
import jakarta.annotation.PreDestroy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialRepository;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialVO;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialRepository;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialVO;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.springframework.stereotype.Component;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import java.time.Duration;
import java.util.Map;
@@ -46,11 +46,11 @@ import java.util.function.Function;
* Builds and caches Aliyun RocketMQ 5.x OpenAPI async clients per credential#region, and
* converts SDK failures into {@link BusinessException} with meaningful HTTP-style codes.
*/
+@Slf4j
+@RequiredArgsConstructor
@Component
public class AliyunClientFactory {
- private static final Logger log = LoggerFactory.getLogger(AliyunClientFactory.class);
-
static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(10);
static final Duration RESPONSE_TIMEOUT = Duration.ofSeconds(20);
static final long DEFAULT_CALL_TIMEOUT_SECONDS = 30L;
@@ -59,10 +59,6 @@ public class AliyunClientFactory {
private final Map<String, AsyncClient> clients = new ConcurrentHashMap<>();
private long callTimeoutSeconds = DEFAULT_CALL_TIMEOUT_SECONDS;
- public AliyunClientFactory(CloudCredentialRepository credentialRepository) {
- this.credentialRepository = credentialRepository;
- }
-
public AsyncClient client(String credentialId, String region) {
String key = cacheKey(credentialId, region);
return clients.computeIfAbsent(key, ignored -> createClient(credentialId, region));
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
index 04fb8788..927e3bd3 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProvider.java
@@ -43,6 +43,8 @@ import com.aliyun.sdk.service.rocketmq20220801.models.ListTopicsResponse;
import com.aliyun.sdk.service.rocketmq20220801.models.ListTopicsResponseBody;
import com.aliyun.sdk.service.rocketmq20220801.models.ResetConsumeOffsetRequest;
import com.aliyun.sdk.service.rocketmq20220801.models.UpdateTopicRequest;
+import org.springframework.util.StringUtils;
+
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.instance.InstanceRepository;
@@ -56,6 +58,7 @@ import org.apache.rocketmq.studio.instance.topic.TopicConsumerVO;
import org.apache.rocketmq.studio.instance.topic.TopicVO;
import org.apache.rocketmq.studio.provider.InstanceProvider;
import org.springframework.stereotype.Component;
+import lombok.RequiredArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@@ -64,6 +67,7 @@ import java.util.List;
* Aliyun RocketMQ 5.x implementation of the instance-scoped operations SPI, backed by the
* OpenAPI async SDK through {@link AliyunClientFactory}.
*/
+@RequiredArgsConstructor
@Component
public class AliyunInstanceProvider implements InstanceProvider {
@@ -79,16 +83,21 @@ public class AliyunInstanceProvider implements InstanceProvider {
private final AliyunClientFactory clientFactory;
private final InstanceRepository instanceRepository;
- public AliyunInstanceProvider(AliyunClientFactory clientFactory, InstanceRepository instanceRepository) {
- this.clientFactory = clientFactory;
- this.instanceRepository = instanceRepository;
- }
-
@Override
public InstanceVendor vendor() {
return InstanceVendor.ALIYUN;
}
+ @Override
+ public int countTopics(String instanceId) {
+ return listTopics(instanceId, null, null).size();
+ }
+
+ @Override
+ public int countGroups(String instanceId) {
+ return listConsumerGroups(instanceId, null).size();
+ }
+
@Override
public List<TopicVO> listTopics(String instanceId, String type, String search) {
Context ctx = resolve(instanceId);
@@ -98,7 +107,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
.instanceId(ctx.cloudInstanceId())
.pageNumber(page)
.pageSize(AliyunConverters.PAGE_SIZE);
- if (!isBlank(search)) {
+ if (!!StringUtils.hasText(search)) {
builder.filter(search);
}
ListTopicsRequest request = builder.build();
@@ -128,7 +137,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
@Override
public TopicVO createTopic(String instanceId, TopicVO topic) {
Context ctx = resolve(instanceId);
- if (topic == null || isBlank(topic.getName())) {
+ if (topic == null || !StringUtils.hasText(topic.getName())) {
throw new BusinessException(400, "Topic name is required");
}
if (topic.getType() == null) {
@@ -150,7 +159,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
@Override
public TopicVO updateTopic(String instanceId, TopicVO topic) {
Context ctx = resolve(instanceId);
- if (topic == null || isBlank(topic.getName())) {
+ if (topic == null || !StringUtils.hasText(topic.getName())) {
throw new BusinessException(400, "Topic name is required");
}
UpdateTopicRequest request = UpdateTopicRequest.builder()
@@ -203,7 +212,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
.instanceId(ctx.cloudInstanceId())
.pageNumber(page)
.pageSize(AliyunConverters.PAGE_SIZE);
- if (!isBlank(search)) {
+ if (!!StringUtils.hasText(search)) {
builder.filter(search);
}
ListConsumerGroupsRequest request = builder.build();
@@ -230,7 +239,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
@Override
public ConsumerGroupVO createConsumerGroup(String instanceId, ConsumerGroupVO group) {
Context ctx = resolve(instanceId);
- if (group == null || isBlank(group.getName())) {
+ if (group == null || !StringUtils.hasText(group.getName())) {
throw new BusinessException(400, "Consumer group name is required");
}
String deliveryOrderType = normalizeDeliveryOrderType(group.getDeliveryOrderType());
@@ -329,7 +338,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
ResetConsumeOffsetRequest.Builder builder = ResetConsumeOffsetRequest.builder()
.instanceId(ctx.cloudInstanceId())
.consumerGroupId(groupName);
- if (!isBlank(topic)) {
+ if (!!StringUtils.hasText(topic)) {
builder.topicName(topic);
}
if (timestamp > 0L) {
@@ -352,13 +361,13 @@ public class AliyunInstanceProvider implements InstanceProvider {
.instanceId(ctx.cloudInstanceId())
.pageNumber(page)
.pageSize(AliyunConverters.MESSAGE_PAGE_SIZE);
- if (!isBlank(topic)) {
+ if (!!StringUtils.hasText(topic)) {
builder.topicName(topic);
}
- if (!isBlank(msgId)) {
+ if (!!StringUtils.hasText(msgId)) {
builder.messageId(msgId);
}
- if (!isBlank(key)) {
+ if (!!StringUtils.hasText(key)) {
builder.messageKey(key);
}
if (startTime != null) {
@@ -378,7 +387,7 @@ public class AliyunInstanceProvider implements InstanceProvider {
}
for (ListMessagesResponseBody.List item : list) {
MessageRecordVO vo = AliyunConverters.toMessageRecord(item);
- if (isBlank(tag) || tag.equals(vo.getTag())) {
+ if (!StringUtils.hasText(tag) || tag.equals(vo.getTag())) {
records.add(vo);
}
}
@@ -407,29 +416,25 @@ public class AliyunInstanceProvider implements InstanceProvider {
}
private Context resolve(String instanceId) {
- if (isBlank(instanceId)) {
+ if (!StringUtils.hasText(instanceId)) {
throw new BusinessException(400, "instanceId is required");
}
InstanceVO instance = instanceRepository.findById(instanceId)
.orElseThrow(() -> new BusinessException(404, "Instance not found: " + instanceId));
- if (isBlank(instance.getCloudInstanceId()) || isBlank(instance.getRegionId())
- || isBlank(instance.getCredentialId())) {
+ if (!StringUtils.hasText(instance.getCloudInstanceId()) || !StringUtils.hasText(instance.getRegionId())
+ || !StringUtils.hasText(instance.getCredentialId())) {
throw new BusinessException(400, "Instance " + instanceId + " is missing Aliyun cloud binding");
}
return new Context(instance.getCloudInstanceId(), instance.getRegionId(), instance.getCredentialId());
}
private static boolean matchesType(String type, TopicVO vo) {
- if (isBlank(type)) {
+ if (!StringUtils.hasText(type)) {
return true;
}
return vo.getType() != null && vo.getType().name().equalsIgnoreCase(type.trim());
}
- private static boolean isBlank(String value) {
- return value == null || value.isBlank();
- }
-
private record Context(String cloudInstanceId, String regionId, String credentialId) {
}
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/AdminClient.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/AdminClient.java
similarity index 84%
rename from server/src/main/java/org/apache/rocketmq/studio/instance/topic/AdminClient.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/AdminClient.java
index 3bd557a4..90e958b9 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/AdminClient.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/AdminClient.java
@@ -14,8 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.instance.topic;
+package org.apache.rocketmq.studio.provider.apache;
+import org.apache.rocketmq.studio.instance.topic.SendMessageVO;
+import org.apache.rocketmq.studio.instance.topic.SendMessageDTO;
+import org.apache.rocketmq.studio.instance.topic.TopicVO;
import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
index 1d351546..a9e4236a 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProvider.java
@@ -17,18 +17,18 @@
package org.apache.rocketmq.studio.provider.apache;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
+import org.apache.rocketmq.studio.instance.InstanceRepository;
import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
import org.apache.rocketmq.studio.instance.group.QueueProgressVO;
import org.apache.rocketmq.studio.instance.group.SubscriptionEntryVO;
import org.apache.rocketmq.studio.instance.message.MessageProvider;
import org.apache.rocketmq.studio.instance.message.MessageRecordVO;
import org.apache.rocketmq.studio.instance.message.TraceRecordVO;
-import org.apache.rocketmq.studio.instance.topic.AdminClient;
-import org.apache.rocketmq.studio.instance.topic.MetadataProvider;
import org.apache.rocketmq.studio.instance.topic.TopicConsumerVO;
import org.apache.rocketmq.studio.instance.topic.TopicVO;
import org.apache.rocketmq.studio.provider.InstanceProvider;
import org.springframework.stereotype.Component;
+import lombok.RequiredArgsConstructor;
import java.util.List;
import java.util.Objects;
@@ -37,26 +37,30 @@ import java.util.Objects;
* Open-source Apache RocketMQ implementation: pure delegation to the existing admin-client
* beans, keeping behavior identical to the pre-provider code path.
*/
+@RequiredArgsConstructor
@Component
public class ApacheInstanceProvider implements InstanceProvider {
private final MetadataProvider metadataProvider;
private final AdminClient adminClient;
private final MessageProvider messageProvider;
-
- public ApacheInstanceProvider(MetadataProvider metadataProvider,
- AdminClient adminClient,
- MessageProvider messageProvider) {
- this.metadataProvider = metadataProvider;
- this.adminClient = adminClient;
- this.messageProvider = messageProvider;
- }
+ private final InstanceRepository instanceRepository;
@Override
public InstanceVendor vendor() {
return InstanceVendor.APACHE;
}
+ @Override
+ public int countTopics(String instanceId) {
+ return (int) instanceRepository.countTopicsByInstance(instanceId);
+ }
+
+ @Override
+ public int countGroups(String instanceId) {
+ return (int) instanceRepository.countGroupsByInstance(instanceId);
+ }
+
@Override
public List<TopicVO> listTopics(String instanceId, String type, String search) {
return metadataProvider.listTopics(null, type, search).stream()
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
similarity index 85%
rename from server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
index fec47fa9..e5ccef5c 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/MetadataProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/MetadataProvider.java
@@ -14,8 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.instance.topic;
+package org.apache.rocketmq.studio.provider.apache;
+import org.apache.rocketmq.studio.instance.topic.TopicConsumerVO;
+import org.apache.rocketmq.studio.instance.topic.BrokerRouteVO;
+import org.apache.rocketmq.studio.instance.topic.TopicVO;
import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
import org.apache.rocketmq.studio.instance.group.QueueProgressVO;
import org.apache.rocketmq.studio.instance.group.SubscriptionEntryVO;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java
new file mode 100644
index 00000000..10da98ce
--- /dev/null
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQAdminClientImpl.java
@@ -0,0 +1,528 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.rocketmq.studio.provider.apache;
+
+import org.apache.rocketmq.client.exception.MQClientException;
+import org.apache.rocketmq.client.producer.DefaultMQProducer;
+import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.TopicConfig;
+import org.apache.rocketmq.common.message.Message;
+import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
+import org.apache.rocketmq.remoting.protocol.ResponseCode;
+import org.apache.rocketmq.remoting.protocol.route.BrokerData;
+import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
+import org.apache.rocketmq.studio.common.exception.BusinessException;
+import org.apache.rocketmq.studio.common.domain.enums.TopicPerm;
+import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
+import org.apache.rocketmq.studio.instance.topic.SendMessageDTO;
+import org.apache.rocketmq.studio.instance.topic.SendMessageVO;
+import org.apache.rocketmq.studio.instance.topic.TopicVO;
+import org.apache.rocketmq.studio.ops.audit.AuditService;
+import org.apache.rocketmq.studio.persistence.entity.RmqGroup;
+import org.apache.rocketmq.studio.persistence.entity.RmqTopic;
+import org.apache.rocketmq.studio.persistence.mapper.RmqGroupMapper;
+import org.apache.rocketmq.studio.persistence.mapper.RmqTopicMapper;
+import org.apache.rocketmq.tools.admin.MQAdminExt;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Real AdminClient implementation backed by the RocketMQ admin API.
+ * Provides topic CRUD, message sending, consumer group CRUD, and offset reset.
+ */
+@Slf4j
+@Service
+@Primary
+@RequiredArgsConstructor
+public class RocketMQAdminClientImpl implements AdminClient {
+
+ private static final String MESSAGE_SENDER_GROUP_PREFIX = "studio-msg-sender";
+
+ private final MqAdminExtFactory adminFactory;
+ private final RocketMQProperties properties;
+ private final RmqTopicMapper topicMapper;
+ private final RmqGroupMapper groupMapper;
+ private final AuditService auditService;
+
+ @Override
+ public TopicVO getTopic(String name) {
+ return adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ var routeData = admin.examineTopicRouteInfo(name);
+ if (routeData == null || routeData.getQueueDatas() == null || routeData.getQueueDatas().isEmpty()) {
+ throw new BusinessException(404, "Topic not found: " + name);
+ }
+ var qd = routeData.getQueueDatas().get(0);
+ TopicVO vo = new TopicVO();
+ vo.setId(name);
+ vo.setName(name);
+ vo.setWriteQueues(qd.getWriteQueueNums());
+ vo.setReadQueues(qd.getReadQueueNums());
+ return vo;
+ } catch (BusinessException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new BusinessException(500, "Failed to get topic: " + e.getMessage());
+ }
+ });
+ }
+
+ @Override
+ public ConsumerGroupVO getConsumerGroup(String name) {
+ return adminFactory.execute(namesrvAddr(), null, admin -> {
+ ConsumerGroupVO vo = new ConsumerGroupVO();
+ vo.setId(name);
+ vo.setName(name);
+ try {
+ var conn = admin.examineConsumerConnectionInfo(name);
+ if (conn != null) {
+ if (conn.getConnectionSet() != null) {
+ vo.setOnlineInstances(conn.getConnectionSet().size());
+ }
+ if (conn.getSubscriptionTable() != null) {
+ vo.setSubscribedTopics(new ArrayList<>(conn.getSubscriptionTable().keySet()));
+ }
+ }
+ } catch (MQClientException exception) {
+ if (exception.getResponseCode() == ResponseCode.CONSUMER_NOT_ONLINE) {
+ log.debug("Consumer group {} is offline", name);
+ return vo;
+ }
+ throw new BusinessException(502, "Failed to get consumer group: " + exception.getMessage());
+ } catch (Exception exception) {
+ throw new BusinessException(502, "Failed to get consumer group: " + exception.getMessage());
+ }
+ return vo;
+ });
+ }
+
+ @Override
+ public TopicVO createTopic(TopicVO topic) {
+ String topicName = topic.getName();
+ int writeQueues = topic.getWriteQueues() > 0 ? topic.getWriteQueues() : 8;
+ int readQueues = topic.getReadQueues() > 0 ? topic.getReadQueues() : 8;
+
+ return adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ String clusterName = getClusterName(admin);
+ // Match on the (cluster_id, name) key: the same topic name can exist in several
+ // clusters, and a name-only lookup would blow up with TooManyResultsException.
+ RmqTopic existing = topicMapper.selectOne(
+ new LambdaQueryWrapper<RmqTopic>()
+ .eq(RmqTopic::getClusterId, clusterName)
+ .eq(RmqTopic::getName, topicName));
+ TopicPerm effectivePerm = topic.getPerm() != null
+ ? topic.getPerm()
+ : existing == null ? TopicPerm.RW : fromRocketMQPerm(existing.getPerm());
+ Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+ if (brokerAddrs.isEmpty()) {
+ throw new BusinessException(500, "No broker available to create topic");
+ }
+
+ TopicConfig topicConfig = new TopicConfig();
+ topicConfig.setTopicName(topicName);
+ topicConfig.setWriteQueueNums(writeQueues);
+ topicConfig.setReadQueueNums(readQueues);
+ topicConfig.setPerm(toRocketMQPerm(effectivePerm));
+
+ for (String addr : brokerAddrs) {
+ admin.createAndUpdateTopicConfig(addr, topicConfig);
+ }
+
+ // Persist to DB. Re-creating a topic that already has a record (for example when
+ // rebuilding a broker route from the console) must update it instead of failing on
+ // the unique (cluster_id, name) key.
+ RmqTopic entity = topicMapper.selectOne(new LambdaQueryWrapper<RmqTopic>()
+ .eq(RmqTopic::getClusterId, clusterName)
+ .eq(RmqTopic::getName, topicName));
+ boolean isNew = entity == null;
+ if (isNew) {
+ entity = new RmqTopic();
+ entity.setName(topicName);
+ entity.setClusterId(clusterName);
+ entity.setCreatedAt(LocalDateTime.now());
+ }
+ if (StringUtils.hasText(topic.getInstanceId())) {
+ entity.setInstanceId(topic.getInstanceId());
+ }
+ entity.setTopicType(topic.getType() != null ? topic.getType().name() : "NORMAL");
+ entity.setReadQueueNums(readQueues);
+ entity.setWriteQueueNums(writeQueues);
+ entity.setPerm(topicConfig.getPerm());
+ if (StringUtils.hasText(topic.getRemark())) {
+ entity.setRemark(topic.getRemark());
+ }
+ entity.setStatus("ACTIVE");
+ entity.setUpdatedAt(LocalDateTime.now());
+ if (isNew) {
+ topicMapper.insert(entity);
+ } else {
+ topicMapper.updateById(entity);
+ }
+
+ auditService.record("CREATE_TOPIC", topicName,
+ "queues=" + writeQueues + "/" + readQueues, "SUCCESS");
+
+ topic.setId(topicName);
+ topic.setWriteQueues(writeQueues);
+ topic.setReadQueues(readQueues);
+ return topic;
+ } catch (BusinessException e) {
+ auditService.record("CREATE_TOPIC", topicName, e.getMessage(), "FAILED");
+ throw e;
+ } catch (Exception e) {
+ auditService.record("CREATE_TOPIC", topicName, e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to create topic: " + e.getMessage());
+ }
+ });
+ }
+
+ @Override
+ public TopicVO updateTopic(TopicVO topic) {
+ String topicName = topic.getName();
+ int writeQueues = topic.getWriteQueues() > 0 ? topic.getWriteQueues() : 8;
+ int readQueues = topic.getReadQueues() > 0 ? topic.getReadQueues() : 8;
+
+ return adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ // Match on the (cluster_id, name) key to avoid ambiguity when several clusters share
+ // the same topic name (a name-only lookup would throw TooManyResultsException).
+ String clusterName = getClusterName(admin);
+ RmqTopic existing = topicMapper.selectOne(
+ new LambdaQueryWrapper<RmqTopic>()
+ .eq(RmqTopic::getClusterId, clusterName)
+ .eq(RmqTopic::getName, topicName));
+ TopicPerm effectivePerm = topic.getPerm() != null
+ ? topic.getPerm()
+ : existing == null ? TopicPerm.RW : fromRocketMQPerm(existing.getPerm());
+ Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+ if (brokerAddrs.isEmpty()) {
+ throw new BusinessException(500, "No broker available to update topic");
+ }
+
+ TopicConfig topicConfig = new TopicConfig();
+ topicConfig.setTopicName(topicName);
+ topicConfig.setWriteQueueNums(writeQueues);
+ topicConfig.setReadQueueNums(readQueues);
+ topicConfig.setPerm(toRocketMQPerm(effectivePerm));
+
+ for (String addr : brokerAddrs) {
+ admin.createAndUpdateTopicConfig(addr, topicConfig);
+ }
+
+ // Update DB record
+ if (existing != null) {
+ existing.setWriteQueueNums(writeQueues);
+ existing.setReadQueueNums(readQueues);
+ existing.setPerm(topicConfig.getPerm());
+ existing.setUpdatedAt(LocalDateTime.now());
+ topicMapper.updateById(existing);
+ }
+
+ auditService.record("UPDATE_TOPIC", topicName,
+ "queues=" + writeQueues + "/" + readQueues, "SUCCESS");
+
+ topic.setId(topicName);
+ topic.setWriteQueues(writeQueues);
+ topic.setReadQueues(readQueues);
+ return topic;
+ } catch (BusinessException e) {
+ auditService.record("UPDATE_TOPIC", topicName, e.getMessage(), "FAILED");
+ throw e;
+ } catch (Exception e) {
+ auditService.record("UPDATE_TOPIC", topicName, e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to update topic: " + e.getMessage());
+ }
+ });
+ }
+
+ @Override
+ public void deleteTopic(String name) {
+ String namesrvAddr = namesrvAddr();
+ adminFactory.execute(namesrvAddr, null, admin -> {
+ try {
+ Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+
+ // Delete from brokers
+ if (!brokerAddrs.isEmpty()) {
+ admin.deleteTopicInBroker(brokerAddrs, name);
+ }
+
+ // Delete from nameserver
+ Set<String> nsAddrs = new HashSet<>();
+ for (String addr : namesrvAddr.split("[;,]")) {
+ String trimmed = addr.trim();
+ if (!trimmed.isEmpty()) {
+ nsAddrs.add(trimmed);
+ }
+ }
+ admin.deleteTopicInNameServer(nsAddrs, getClusterName(admin), name);
+
+ // Delete from DB
+ topicMapper.delete(new LambdaQueryWrapper<RmqTopic>().eq(RmqTopic::getName, name));
+
+ auditService.record("DELETE_TOPIC", name, "", "SUCCESS");
+ return null;
+ } catch (BusinessException e) {
+ auditService.record("DELETE_TOPIC", name, e.getMessage(), "FAILED");
+ throw e;
+ } catch (Exception e) {
+ auditService.record("DELETE_TOPIC", name, e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to delete topic: " + e.getMessage());
+ }
+ });
+ }
+
+ @Override
+ public SendMessageVO sendMessage(SendMessageDTO request) {
+ String namesrvAddr = namesrvAddr();
+
+ DefaultMQProducer producer = new DefaultMQProducer(nextMessageSenderGroup());
+ producer.setNamesrvAddr(namesrvAddr);
+ producer.setSendMsgTimeout(5000);
+
+ try {
+ producer.start();
+
+ String topic = request.getTopic();
+ String tag = request.getTag() != null ? request.getTag() : "";
+ String key = request.getKey() != null ? request.getKey() : "";
+ String body = request.getBody() != null ? request.getBody() : "";
+
+ String fullTopic = tag.isEmpty() ? topic : topic + ":" + tag;
+ Message msg = new Message(topic, tag, key, body.getBytes(StandardCharsets.UTF_8));
+
+ // Add custom properties
+ if (request.getProperties() != null) {
+ for (Map.Entry<String, String> entry : request.getProperties().entrySet()) {
+ msg.putUserProperty(entry.getKey(), entry.getValue());
+ }
+ }
+
+ SendResult sendResult = producer.send(msg);
+
+ // The message is already delivered by now; an audit write failure must not turn a
+ // successful send into an error, or callers would retry and duplicate the message.
+ try {
+ auditService.record("SEND_MESSAGE", topic,
+ "tag=" + tag + ", key=" + key + ", msgId=" + sendResult.getMsgId(), "SUCCESS");
+ } catch (Exception auditFailure) {
+ log.warn("Failed to record send message audit: {}", auditFailure.getMessage());
+ }
+
+ return SendMessageVO.builder()
+ .msgId(sendResult.getMsgId())
+ .sendTime(System.currentTimeMillis())
+ .offsetMsgId(sendResult.getOffsetMsgId())
+ .build();
+ } catch (Exception e) {
+ auditService.record("SEND_MESSAGE", request.getTopic(), e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to send message: " + e.getMessage());
+ } finally {
+ producer.shutdown();
+ }
+ }
+
+ static String nextMessageSenderGroup() {
+ return ShortLivedClientName.next(MESSAGE_SENDER_GROUP_PREFIX);
+ }
+
+ @Override
+ public ConsumerGroupVO createConsumerGroup(ConsumerGroupVO group) {
+ String groupName = group.getName();
+
+ return adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+ if (brokerAddrs.isEmpty()) {
+ throw new BusinessException(500, "No broker available to create consumer group");
+ }
+
+ SubscriptionGroupConfig config = new SubscriptionGroupConfig();
+ config.setGroupName(groupName);
+ config.setConsumeEnable(true);
+ config.setConsumeBroadcastEnable(true);
+ config.setRetryQueueNums(1);
+ config.setRetryMaxTimes(group.getRetryMaxTimes() > 0 ? group.getRetryMaxTimes() : 16);
+
+ for (String addr : brokerAddrs) {
+ admin.createAndUpdateSubscriptionGroupConfig(addr, config);
+ }
+
+ // Persist to DB, upserting so re-creating an existing group does not violate the
+ // unique (cluster_id, name) key.
+ String groupClusterName = getClusterName(admin);
+ RmqGroup entity = groupMapper.selectOne(new LambdaQueryWrapper<RmqGroup>()
+ .eq(RmqGroup::getClusterId, groupClusterName)
+ .eq(RmqGroup::getName, groupName));
+ boolean isNewGroup = entity == null;
+ if (isNewGroup) {
+ entity = new RmqGroup();
+ entity.setName(groupName);
+ entity.setClusterId(groupClusterName);
+ entity.setCreatedAt(LocalDateTime.now());
+ }
+ if (StringUtils.hasText(group.getInstanceId())) {
+ entity.setInstanceId(group.getInstanceId());
+ }
+ entity.setConsumeType(group.getConsumeType() != null ? group.getConsumeType().name() : "CLUSTERING");
+ entity.setMessageModel(group.getSubscriptionMode() != null ? group.getSubscriptionMode().name() : "Push");
+ entity.setMaxRetry(config.getRetryMaxTimes());
+ entity.setStatus("ACTIVE");
+ entity.setUpdatedAt(LocalDateTime.now());
+ if (isNewGroup) {
+ groupMapper.insert(entity);
+ } else {
+ groupMapper.updateById(entity);
+ }
+
+ auditService.record("CREATE_GROUP", groupName,
+ "retryMaxTimes=" + config.getRetryMaxTimes(), "SUCCESS");
+
+ group.setId(groupName);
+ return group;
+ } catch (BusinessException e) {
+ auditService.record("CREATE_GROUP", groupName, e.getMessage(), "FAILED");
+ throw e;
+ } catch (Exception e) {
+ auditService.record("CREATE_GROUP", groupName, e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to create consumer group: " + e.getMessage());
+ }
+ });
+ }
+
+ @Override
+ public void deleteConsumerGroup(String name) {
+ adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ Set<String> brokerAddrs = getAllMasterBrokerAddrs(admin);
+
+ for (String addr : brokerAddrs) {
+ admin.deleteSubscriptionGroup(addr, name, true);
+ }
+
+ // Delete from DB
+ groupMapper.delete(new LambdaQueryWrapper<RmqGroup>().eq(RmqGroup::getName, name));
+
+ auditService.record("DELETE_GROUP", name, "", "SUCCESS");
+ return null;
+ } catch (BusinessException e) {
+ auditService.record("DELETE_GROUP", name, e.getMessage(), "FAILED");
+ throw e;
+ } catch (Exception e) {
+ auditService.record("DELETE_GROUP", name, e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to delete consumer group: " + e.getMessage());
+ }
+ });
+ }
+
+ @Override
+ public void resetOffset(String name, long timestamp, String topic) {
+ adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ admin.resetOffsetByTimestamp(getClusterName(admin), topic, name, timestamp, false);
+ auditService.record("RESET_OFFSET", name,
+ "topic=" + topic + ", timestamp=" + timestamp, "SUCCESS");
+ return null;
+ } catch (Exception e) {
+ auditService.record("RESET_OFFSET", name, e.getMessage(), "FAILED");
+ throw new BusinessException(500, "Failed to reset offset: " + e.getMessage());
+ }
+ });
+ }
+
+ // ── Helper methods ──────────────────────────────────────────────────
+
+ /**
+ * Returns the configured default NameServer address, failing fast when the studio has no
+ * RocketMQ endpoint configured (equivalent to the former absent admin bean).
+ */
+ private String namesrvAddr() {
+ String namesrvAddr = properties.getNamesrvAddr();
+ if (!StringUtils.hasText(namesrvAddr)) {
+ throw new BusinessException(503, "RocketMQ admin not connected");
+ }
+ return namesrvAddr;
+ }
+
+ private Set<String> getAllMasterBrokerAddrs(MQAdminExt admin) throws Exception {
+ Set<String> addrs = new HashSet<>();
+ ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();
+ if (clusterInfo == null || clusterInfo.getBrokerAddrTable() == null) {
+ return addrs;
+ }
+
+ for (BrokerData brokerData : clusterInfo.getBrokerAddrTable().values()) {
+ if (brokerData.getBrokerAddrs() == null) {
+ continue;
+ }
+ // Use master address (brokerId = 0) preferentially
+ String masterAddr = brokerData.getBrokerAddrs().get(0L);
+ if (masterAddr == null && !brokerData.getBrokerAddrs().isEmpty()) {
+ masterAddr = brokerData.getBrokerAddrs().values().iterator().next();
+ }
+ if (masterAddr != null) {
+ addrs.add(masterAddr);
+ }
+ }
+ return addrs;
+ }
+
+ private String getClusterName(MQAdminExt admin) {
+ try {
+ ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();
+ if (clusterInfo != null && clusterInfo.getClusterAddrTable() != null
+ && !clusterInfo.getClusterAddrTable().isEmpty()) {
+ return clusterInfo.getClusterAddrTable().keySet().iterator().next();
+ }
+ } catch (Exception ignored) {
+ }
+ return "DefaultCluster";
+ }
+
+ private int toRocketMQPerm(TopicPerm perm) {
+ if (perm == TopicPerm.RO) {
+ return 4;
+ }
+ if (perm == TopicPerm.WO) {
+ return 2;
+ }
+ return 6;
+ }
+
+ private TopicPerm fromRocketMQPerm(Integer perm) {
+ if (perm != null && perm == 4) {
+ return TopicPerm.RO;
+ }
+ if (perm != null && perm == 2) {
+ return TopicPerm.WO;
+ }
+ return TopicPerm.RW;
+ }
+}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQBrokerConfigService.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQBrokerConfigService.java
similarity index 65%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQBrokerConfigService.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQBrokerConfigService.java
index 67415674..15efe4d2 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQBrokerConfigService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQBrokerConfigService.java
@@ -14,61 +14,62 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
+import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
import org.apache.rocketmq.studio.cluster.config.ClusterConfigVO;
import org.apache.rocketmq.studio.common.domain.enums.FlushDiskType;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.ops.audit.AuditService;
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
import java.util.Properties;
@Slf4j
@Service
+@RequiredArgsConstructor
public class RocketMQBrokerConfigService {
- private final DefaultMQAdminExt adminExt;
+ private final MqAdminExtFactory adminFactory;
+ private final RocketMQProperties properties;
private final AuditService auditService;
- public RocketMQBrokerConfigService(@Nullable DefaultMQAdminExt adminExt, AuditService auditService) {
- this.adminExt = adminExt;
- this.auditService = auditService;
- }
-
/**
* Read broker config from the live broker via admin API.
*/
public ClusterConfigVO getBrokerConfig(String brokerAddr) {
- requireAdmin();
- try {
- Properties props = adminExt.getBrokerConfig(brokerAddr);
- return mapToClusterConfigVO(props);
- } catch (Exception e) {
- log.error("Failed to get broker config from {}", brokerAddr, e);
- throw new BusinessException(500, "Failed to get broker config: " + e.getMessage());
- }
+ return adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ Properties props = admin.getBrokerConfig(brokerAddr);
+ return mapToClusterConfigVO(props);
+ } catch (Exception e) {
+ log.error("Failed to get broker config from {}", brokerAddr, e);
+ throw new BusinessException(500, "Failed to get broker config: " + e.getMessage());
+ }
+ });
}
/**
* Update broker config on the live broker via admin API, then record audit.
*/
public void updateBrokerConfig(String brokerAddr, String clusterId, Properties newConfig) {
- requireAdmin();
- try {
- adminExt.updateBrokerConfig(brokerAddr, newConfig);
- String detail = "brokerAddr=" + brokerAddr + ", config=" + newConfig;
- auditService.record("UPDATE_BROKER_CONFIG", "CLUSTER:" + clusterId, detail, "SUCCESS");
- log.info("Broker config updated successfully: {}", brokerAddr);
- } catch (Exception e) {
- log.error("Failed to update broker config at {}", brokerAddr, e);
- String detail = "brokerAddr=" + brokerAddr + ", error=" + e.getMessage();
- auditService.record("UPDATE_BROKER_CONFIG", "CLUSTER:" + clusterId, detail, "FAILURE");
- throw new BusinessException(500, "Failed to update broker config: " + e.getMessage());
- }
+ adminFactory.execute(namesrvAddr(), null, admin -> {
+ try {
+ admin.updateBrokerConfig(brokerAddr, newConfig);
+ String detail = "brokerAddr=" + brokerAddr + ", config=" + newConfig;
+ auditService.record("UPDATE_BROKER_CONFIG", "CLUSTER:" + clusterId, detail, "SUCCESS");
+ log.info("Broker config updated successfully: {}", brokerAddr);
+ return null;
+ } catch (Exception e) {
+ log.error("Failed to update broker config at {}", brokerAddr, e);
+ String detail = "brokerAddr=" + brokerAddr + ", error=" + e.getMessage();
+ auditService.record("UPDATE_BROKER_CONFIG", "CLUSTER:" + clusterId, detail, "FAILURE");
+ throw new BusinessException(500, "Failed to update broker config: " + e.getMessage());
+ }
+ });
}
private ClusterConfigVO mapToClusterConfigVO(Properties props) {
@@ -105,9 +106,11 @@ public class RocketMQBrokerConfigService {
}
}
- private void requireAdmin() {
- if (adminExt == null) {
+ private String namesrvAddr() {
+ String namesrvAddr = properties.getNamesrvAddr();
+ if (!StringUtils.hasText(namesrvAddr)) {
throw new BusinessException(503, "RocketMQ admin is not configured. Set studio.rocketmq.namesrv-addr.");
}
+ return namesrvAddr;
}
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQClientProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
similarity index 87%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQClientProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
index 48760cf6..574f0d3f 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQClientProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClientProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.remoting.protocol.LanguageCode;
@@ -29,17 +29,18 @@ import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.studio.cluster.client.ClientConnectionVO;
import org.apache.rocketmq.studio.cluster.client.ClientProvider;
+import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
import org.apache.rocketmq.studio.cluster.broker.RuntimeAdminClientResolver;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.common.domain.enums.ClientLanguage;
import org.apache.rocketmq.studio.common.domain.enums.ClientType;
import org.apache.rocketmq.studio.common.domain.enums.Protocol;
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
import org.apache.rocketmq.tools.admin.MQAdminExt;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@@ -58,18 +59,14 @@ import java.util.Set;
@Slf4j
@Service
@Primary
+@RequiredArgsConstructor
public class RocketMQClientProvider implements ClientProvider {
private static final long SUBSCRIPTION_GROUP_TIMEOUT_MILLIS = 5000L;
- private final ObjectProvider<DefaultMQAdminExt> adminExtProvider;
+ private final MqAdminExtFactory adminFactory;
private final RuntimeAdminClientResolver runtimeAdminClientResolver;
-
- public RocketMQClientProvider(ObjectProvider<DefaultMQAdminExt> adminExtProvider,
- RuntimeAdminClientResolver runtimeAdminClientResolver) {
- this.adminExtProvider = adminExtProvider;
- this.runtimeAdminClientResolver = runtimeAdminClientResolver;
- }
+ private final RocketMQProperties properties;
@Override
public List<ClientConnectionVO> findConnections(String instanceId, String clusterId, String type) {
@@ -90,30 +87,35 @@ public class RocketMQClientProvider implements ClientProvider {
@Override
public List<ClientConnectionVO> findProducerConnections(String topic, String producerGroup) {
- DefaultMQAdminExt adminExt = requireAdminExt();
- try {
- ProducerConnection producerConnection =
- adminExt.examineProducerConnectionInfo(producerGroup, topic);
- if (producerConnection == null || producerConnection.getConnectionSet() == null) {
- return List.of();
- }
- return producerConnection.getConnectionSet().stream()
- .filter(Objects::nonNull)
- .map(connection -> toConnectionVO(
- connection, ClientType.Producer, topic, producerGroup, null))
- .toList();
- } catch (MQClientException e) {
- if (isTopicNotExist(e)) {
- // A non-existent topic is a normal "nothing here" outcome — the client
- // page should show an empty list, not a 502 that looks like a failure.
- return List.of();
- }
- throw new BusinessException(502,
- "Failed to query producer connections: " + rootMessage(e));
- } catch (Exception e) {
- throw new BusinessException(502,
- "Failed to query producer connections: " + rootMessage(e));
+ String namesrvAddr = properties.getNamesrvAddr();
+ if (!StringUtils.hasText(namesrvAddr)) {
+ throw new BusinessException(501, "Client connection provider is not configured");
}
+ return adminFactory.execute(namesrvAddr, null, admin -> {
+ try {
+ ProducerConnection producerConnection =
+ admin.examineProducerConnectionInfo(producerGroup, topic);
+ if (producerConnection == null || producerConnection.getConnectionSet() == null) {
+ return List.<ClientConnectionVO>of();
+ }
+ return producerConnection.getConnectionSet().stream()
+ .filter(Objects::nonNull)
+ .map(connection -> toConnectionVO(
+ connection, ClientType.Producer, topic, producerGroup, null))
+ .toList();
+ } catch (MQClientException e) {
+ if (isTopicNotExist(e)) {
+ // A non-existent topic is a normal "nothing here" outcome — the client
+ // page should show an empty list, not a 502 that looks like a failure.
+ return List.<ClientConnectionVO>of();
+ }
+ throw new BusinessException(502,
+ "Failed to query producer connections: " + rootMessage(e));
+ } catch (Exception e) {
+ throw new BusinessException(502,
+ "Failed to query producer connections: " + rootMessage(e));
+ }
+ });
}
private boolean isTopicNotExist(MQClientException e) {
@@ -336,14 +338,6 @@ public class RocketMQClientProvider implements ClientProvider {
|| group.startsWith("CID_HOUSEKEEPING");
}
- private DefaultMQAdminExt requireAdminExt() {
- DefaultMQAdminExt adminExt = adminExtProvider.getIfAvailable();
- if (adminExt == null) {
- throw new BusinessException(501, "Client connection provider is not configured");
- }
- return adminExt;
- }
-
private String rootMessage(Throwable error) {
Throwable current = error;
while (current.getCause() != null) {
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQClusterProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
similarity index 68%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQClusterProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
index 7d5c7efd..bdf0990b 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQClusterProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQClusterProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
import org.apache.rocketmq.remoting.protocol.body.KVTable;
@@ -22,15 +22,16 @@ import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.studio.cluster.broker.BrokerVO;
import org.apache.rocketmq.studio.cluster.broker.ClusterProvider;
import org.apache.rocketmq.studio.cluster.broker.ClusterVO;
+import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
import org.apache.rocketmq.studio.cluster.nameserver.NameServerVO;
import org.apache.rocketmq.studio.common.domain.enums.BrokerStatus;
import org.apache.rocketmq.studio.common.domain.enums.ClusterStatus;
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collections;
@@ -39,54 +40,49 @@ import java.util.Map;
import java.util.Set;
/**
- * Real cluster discovery implementation using DefaultMQAdminExt.
- * Falls back to returning empty results when adminExt is not configured or connection fails.
+ * Real cluster discovery implementation using the RocketMQ admin API.
+ * Falls back to returning empty results when no NameServer is configured or connection fails.
*/
+@Slf4j
@Service
@Primary
+@RequiredArgsConstructor
public class RocketMQClusterProvider implements ClusterProvider {
- private static final Logger log = LoggerFactory.getLogger(RocketMQClusterProvider.class);
-
- private final DefaultMQAdminExt adminExt;
+ private final MqAdminExtFactory adminFactory;
private final RocketMQProperties properties;
- @Autowired
- public RocketMQClusterProvider(
- @Autowired(required = false) DefaultMQAdminExt adminExt,
- RocketMQProperties properties) {
- this.adminExt = adminExt;
- this.properties = properties;
- }
-
@Override
public List<ClusterVO> discoverClusters() {
- if (adminExt == null) {
- log.debug("DefaultMQAdminExt not configured, returning empty cluster list");
+ String namesrvAddr = properties.getNamesrvAddr();
+ if (!StringUtils.hasText(namesrvAddr)) {
+ log.debug("NameServer address not configured, returning empty cluster list");
return Collections.emptyList();
}
try {
- ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
- if (clusterInfo == null || clusterInfo.getClusterAddrTable() == null) {
- return Collections.emptyList();
- }
+ return adminFactory.execute(namesrvAddr, null, admin -> {
+ ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();
+ if (clusterInfo == null || clusterInfo.getClusterAddrTable() == null) {
+ return Collections.<ClusterVO>emptyList();
+ }
- Map<String, Set<String>> clusterAddrTable = clusterInfo.getClusterAddrTable();
- Map<String, BrokerData> brokerAddrTable = clusterInfo.getBrokerAddrTable();
+ Map<String, Set<String>> clusterAddrTable = clusterInfo.getClusterAddrTable();
+ Map<String, BrokerData> brokerAddrTable = clusterInfo.getBrokerAddrTable();
- List<ClusterVO> clusters = new ArrayList<>();
- for (Map.Entry<String, Set<String>> entry : clusterAddrTable.entrySet()) {
- String clusterName = entry.getKey();
- Set<String> brokerNames = entry.getValue();
+ List<ClusterVO> clusters = new ArrayList<>();
+ for (Map.Entry<String, Set<String>> entry : clusterAddrTable.entrySet()) {
+ String clusterName = entry.getKey();
+ Set<String> brokerNames = entry.getValue();
- List<BrokerVO> brokers = buildBrokerList(brokerNames, brokerAddrTable);
- List<NameServerVO> nameServers = buildNameServerList();
+ List<BrokerVO> brokers = buildBrokerList(admin, brokerNames, brokerAddrTable);
+ List<NameServerVO> nameServers = buildNameServerList();
- ClusterVO cluster = buildClusterVO(clusterName, brokers, nameServers);
- clusters.add(cluster);
- }
- return clusters;
+ ClusterVO cluster = buildClusterVO(clusterName, brokers, nameServers);
+ clusters.add(cluster);
+ }
+ return clusters;
+ });
} catch (Exception e) {
log.warn("Failed to discover clusters via NameServer: {}", e.getMessage());
return Collections.emptyList();
@@ -95,29 +91,32 @@ public class RocketMQClusterProvider implements ClusterProvider {
@Override
public ClusterVO refreshClusterDetail(String clusterId) {
- if (adminExt == null) {
- log.debug("DefaultMQAdminExt not configured, cannot refresh cluster detail");
+ String namesrvAddr = properties.getNamesrvAddr();
+ if (!StringUtils.hasText(namesrvAddr)) {
+ log.debug("NameServer address not configured, cannot refresh cluster detail");
return null;
}
try {
- ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
- if (clusterInfo == null || clusterInfo.getClusterAddrTable() == null) {
- return null;
- }
+ return adminFactory.execute(namesrvAddr, null, admin -> {
+ ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();
+ if (clusterInfo == null || clusterInfo.getClusterAddrTable() == null) {
+ return null;
+ }
- Map<String, Set<String>> clusterAddrTable = clusterInfo.getClusterAddrTable();
- Map<String, BrokerData> brokerAddrTable = clusterInfo.getBrokerAddrTable();
+ Map<String, Set<String>> clusterAddrTable = clusterInfo.getClusterAddrTable();
+ Map<String, BrokerData> brokerAddrTable = clusterInfo.getBrokerAddrTable();
- Set<String> brokerNames = clusterAddrTable.get(clusterId);
- if (brokerNames == null) {
- return null;
- }
+ Set<String> brokerNames = clusterAddrTable.get(clusterId);
+ if (brokerNames == null) {
+ return null;
+ }
- List<BrokerVO> brokers = buildBrokerList(brokerNames, brokerAddrTable);
- List<NameServerVO> nameServers = buildNameServerList();
+ List<BrokerVO> brokers = buildBrokerList(admin, brokerNames, brokerAddrTable);
+ List<NameServerVO> nameServers = buildNameServerList();
- return buildClusterVO(clusterId, brokers, nameServers);
+ return buildClusterVO(clusterId, brokers, nameServers);
+ });
} catch (Exception e) {
log.warn("Failed to refresh cluster detail for {}: {}", clusterId, e.getMessage());
return null;
@@ -144,7 +143,7 @@ public class RocketMQClusterProvider implements ClusterProvider {
return cluster;
}
- private List<BrokerVO> buildBrokerList(Set<String> brokerNames,
+ private List<BrokerVO> buildBrokerList(MQAdminExt admin, Set<String> brokerNames,
Map<String, BrokerData> brokerAddrTable) {
List<BrokerVO> brokers = new ArrayList<>();
if (brokerNames == null || brokerAddrTable == null) {
@@ -172,16 +171,16 @@ public class RocketMQClusterProvider implements ClusterProvider {
.status(BrokerStatus.running);
// Try to get runtime info for version and TPS
- enrichBrokerWithRuntimeInfo(builder, masterAddr);
+ enrichBrokerWithRuntimeInfo(admin, builder, masterAddr);
brokers.add(builder.build());
}
return brokers;
}
- private void enrichBrokerWithRuntimeInfo(BrokerVO.BrokerVOBuilder builder, String brokerAddr) {
+ private void enrichBrokerWithRuntimeInfo(MQAdminExt admin, BrokerVO.BrokerVOBuilder builder, String brokerAddr) {
try {
- KVTable runtimeInfo = adminExt.fetchBrokerRuntimeStats(brokerAddr);
+ KVTable runtimeInfo = admin.fetchBrokerRuntimeStats(brokerAddr);
if (runtimeInfo == null || runtimeInfo.getTable() == null) {
return;
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDLQProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java
similarity index 96%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDLQProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java
index bb49f96f..138df1f5 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDLQProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDLQProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
@@ -35,11 +35,11 @@ import org.apache.rocketmq.studio.instance.dlq.DLQProvider;
import org.apache.rocketmq.studio.instance.dlq.DLQResendResultVO;
import org.apache.rocketmq.studio.ops.audit.AuditService;
import org.apache.rocketmq.tools.admin.MQAdminExt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -54,24 +54,18 @@ import java.util.Set;
* Real {@link DLQProvider} backed by the RocketMQ admin API. Lists dead-letter groups by scanning
* {@code %DLQ%} topics and resends dead-letter messages back to a target topic.
*/
+@Slf4j
+@RequiredArgsConstructor
@Service
@Primary
public class RocketMQDLQProvider implements DLQProvider {
- private static final Logger log = LoggerFactory.getLogger(RocketMQDLQProvider.class);
-
private static final long ONE_HOUR_MILLIS = 3600_000L;
private static final int RESEND_HARD_CAP = 5000;
private final RuntimeAdminClientResolver runtimeAdminClientResolver;
private final AuditService auditService;
- public RocketMQDLQProvider(RuntimeAdminClientResolver runtimeAdminClientResolver,
- AuditService auditService) {
- this.runtimeAdminClientResolver = runtimeAdminClientResolver;
- this.auditService = auditService;
- }
-
@Override
public List<DLQGroupVO> listDLQGroups(String instanceId) {
return runtimeAdminClientResolver.execute(instanceId, this::listDLQGroups);
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDashboardProvider.java
similarity index 91%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDashboardProvider.java
index 0b7214de..6ffd6270 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQDashboardProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQDashboardProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import java.util.ArrayList;
import java.util.HashSet;
@@ -28,44 +28,46 @@ import org.apache.rocketmq.remoting.protocol.body.SubscriptionGroupWrapper;
import org.apache.rocketmq.remoting.protocol.body.TopicList;
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
+import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
import org.apache.rocketmq.studio.common.domain.enums.ClusterStatus;
import org.apache.rocketmq.studio.common.domain.enums.ClusterType;
import org.apache.rocketmq.studio.ops.dashboard.ClusterOverviewVO;
import org.apache.rocketmq.studio.ops.dashboard.DashboardDataVO;
import org.apache.rocketmq.studio.ops.dashboard.DashboardProvider;
import org.apache.rocketmq.studio.ops.dashboard.DashboardStatsVO;
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.springframework.context.annotation.Primary;
-import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
+@RequiredArgsConstructor
@Service
@Primary
public class RocketMQDashboardProvider implements DashboardProvider {
- private static final Logger log = LoggerFactory.getLogger(RocketMQDashboardProvider.class);
-
private static final Set<String> SYSTEM_TOPIC_PREFIXES = Set.of(
"rmq_sys_", "SCHEDULE_TOPIC_", "RMQ_SYS_", "broker_", "%RETRY%", "%DLQ%",
"TBW102", "SELF_TEST_TOPIC", "BenchmarkTest", "OFFSET_MOVED_EVENT",
"DefaultCluster", "broker-a", "broker-b"
);
- private final DefaultMQAdminExt adminExt;
-
- public RocketMQDashboardProvider(@Nullable DefaultMQAdminExt adminExt) {
- this.adminExt = adminExt;
- }
+ private final MqAdminExtFactory adminFactory;
+ private final RocketMQProperties properties;
@Override
public DashboardDataVO getDashboardData() {
- if (adminExt == null) {
- log.warn("DefaultMQAdminExt not available, returning empty dashboard");
+ String namesrvAddr = properties.getNamesrvAddr();
+ if (!StringUtils.hasText(namesrvAddr)) {
+ log.warn("NameServer address not configured, returning empty dashboard");
return emptyDashboard();
}
+ return adminFactory.execute(namesrvAddr, null, this::collectDashboardData);
+ }
+ private DashboardDataVO collectDashboardData(MQAdminExt admin) {
int totalClusters = 0;
int totalBrokers = 0;
int totalTopics = 0;
@@ -76,7 +78,7 @@ public class RocketMQDashboardProvider implements DashboardProvider {
List<ClusterOverviewVO> clusters = new ArrayList<>();
try {
- ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
+ ClusterInfo clusterInfo = admin.examineBrokerClusterInfo();
if (clusterInfo == null) {
log.warn("NameServer returned no cluster topology, returning empty dashboard");
return emptyDashboard();
@@ -112,7 +114,7 @@ public class RocketMQDashboardProvider implements DashboardProvider {
// Count topics
try {
- TopicList topicList = adminExt.fetchAllTopicList();
+ TopicList topicList = admin.fetchAllTopicList();
Set<String> topics = topicList.getTopicList();
totalTopics = (int) topics.stream()
.filter(t -> !isSystemTopic(t))
@@ -125,7 +127,7 @@ public class RocketMQDashboardProvider implements DashboardProvider {
Set<String> allGroups = new HashSet<>();
for (String brokerAddr : masterAddrs) {
try {
- SubscriptionGroupWrapper subscriptionGroupWrapper = adminExt.getAllSubscriptionGroup(brokerAddr, 5000);
+ SubscriptionGroupWrapper subscriptionGroupWrapper = admin.getAllSubscriptionGroup(brokerAddr, 5000);
if (subscriptionGroupWrapper != null && subscriptionGroupWrapper.getSubscriptionGroupTable() != null) {
for (Map.Entry<String, SubscriptionGroupConfig> entry :
subscriptionGroupWrapper.getSubscriptionGroupTable().entrySet()) {
@@ -141,7 +143,7 @@ public class RocketMQDashboardProvider implements DashboardProvider {
// Get runtime stats for TPS
try {
- KVTable runtimeInfo = adminExt.fetchBrokerRuntimeStats(brokerAddr);
+ KVTable runtimeInfo = admin.fetchBrokerRuntimeStats(brokerAddr);
if (runtimeInfo != null && runtimeInfo.getTable() != null) {
Map<String, String> table = runtimeInfo.getTable();
tpsIn += parseTps(table.get("putTps"));
@@ -177,7 +179,7 @@ public class RocketMQDashboardProvider implements DashboardProvider {
String masterAddr = brokerData.getBrokerAddrs().get(0L);
if (masterAddr != null) {
try {
- KVTable rt = adminExt.fetchBrokerRuntimeStats(masterAddr);
+ KVTable rt = admin.fetchBrokerRuntimeStats(masterAddr);
if (rt != null && rt.getTable() != null) {
clusterTpsIn += (int) parseTps(rt.getTable().get("putTps"));
clusterTpsOut += (int) parseTps(rt.getTable().get("getTransferedTps"));
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
similarity index 96%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
index f23d7b7e..3dee1e9f 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMessageProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMessageProvider.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import org.apache.rocketmq.client.QueryResult;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
@@ -31,16 +31,15 @@ import org.apache.rocketmq.studio.instance.message.MessageProvider;
import org.apache.rocketmq.studio.instance.message.MessageRecordVO;
import org.apache.rocketmq.studio.instance.message.TraceNodeVO;
import org.apache.rocketmq.studio.instance.message.TraceRecordVO;
-import org.apache.rocketmq.studio.queryhistory.QueryHistoryService;
+import org.apache.rocketmq.studio.instance.message.QueryHistoryService;
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
import org.apache.rocketmq.tools.admin.api.MessageTrack;
import org.apache.rocketmq.tools.admin.api.TrackType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
@@ -62,12 +61,12 @@ import java.util.Set;
* message id, by business key and by topic + time range, as well as message trace retrieval.
* Falls back to empty results when adminExt is not configured or a query fails.
*/
+@Slf4j
+@RequiredArgsConstructor
@Service
@Primary
public class RocketMQMessageProvider implements MessageProvider {
- private static final Logger log = LoggerFactory.getLogger(RocketMQMessageProvider.class);
-
private static final String TRACE_TOPIC = "RMQ_SYS_TRACE_TOPIC";
private static final char FIELD_SEPARATOR = '\u0001';
private static final int KEY_QUERY_MAX = 64;
@@ -81,21 +80,10 @@ public class RocketMQMessageProvider implements MessageProvider {
private static final long ONE_HOUR_MILLIS = 3600_000L;
private static final long ONE_DAY_MILLIS = 24 * ONE_HOUR_MILLIS;
- private final ObjectProvider<DefaultMQAdminExt> adminExtProvider;
private final RuntimeAdminClientResolver runtimeAdminClientResolver;
private final QueryHistoryService queryHistoryService;
private final RocketMQProperties properties;
- public RocketMQMessageProvider(ObjectProvider<DefaultMQAdminExt> adminExtProvider,
- RuntimeAdminClientResolver runtimeAdminClientResolver,
- QueryHistoryService queryHistoryService,
- RocketMQProperties properties) {
- this.adminExtProvider = adminExtProvider;
- this.runtimeAdminClientResolver = runtimeAdminClientResolver;
- this.queryHistoryService = queryHistoryService;
- this.properties = properties;
- }
-
@Override
public List<MessageRecordVO> queryMessages(String instanceId, String topic, String msgId, String tag, String key,
Long startTime, Long endTime) {
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMetadataProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
similarity index 52%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMetadataProvider.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
index 75f83344..90233979 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQMetadataProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQMetadataProvider.java
@@ -14,20 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.remoting.protocol.admin.ConsumeStats;
import org.apache.rocketmq.remoting.protocol.admin.OffsetWrapper;
-import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
import org.apache.rocketmq.remoting.protocol.body.GroupList;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.remoting.protocol.route.QueueData;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
+import org.apache.rocketmq.studio.cluster.broker.MqAdminExtFactory;
import org.apache.rocketmq.studio.common.domain.enums.ConsumeType;
import org.apache.rocketmq.studio.common.domain.enums.TopicPerm;
import org.apache.rocketmq.studio.common.domain.enums.TopicType;
@@ -35,20 +35,17 @@ import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
import org.apache.rocketmq.studio.instance.group.QueueProgressVO;
import org.apache.rocketmq.studio.instance.group.SubscriptionEntryVO;
import org.apache.rocketmq.studio.instance.topic.BrokerRouteVO;
-import org.apache.rocketmq.studio.instance.topic.MetadataProvider;
import org.apache.rocketmq.studio.instance.topic.TopicConsumerVO;
import org.apache.rocketmq.studio.instance.topic.TopicVO;
import org.apache.rocketmq.studio.persistence.entity.RmqGroup;
import org.apache.rocketmq.studio.persistence.entity.RmqTopic;
import org.apache.rocketmq.studio.persistence.mapper.RmqGroupMapper;
import org.apache.rocketmq.studio.persistence.mapper.RmqTopicMapper;
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.Collections;
@@ -63,15 +60,15 @@ import java.util.Set;
*
* <p>Topic and consumer group listings are served from the studio metadata database, which is the
* source of record: creation writes there and reads never fall back to the broker. Route,
- * consumer, progress and subscription queries stay live through DefaultMQAdminExt, so a record
- * without a broker route surfaces as an empty route list instead of being hidden.
+ * consumer, progress and subscription queries stay live through the RocketMQ admin API, so a
+ * record without a broker route surfaces as an empty route list instead of being hidden.
*/
+@Slf4j
@Service
@Primary
+@RequiredArgsConstructor
public class RocketMQMetadataProvider implements MetadataProvider {
- private static final Logger log = LoggerFactory.getLogger(RocketMQMetadataProvider.class);
-
private static final Set<String> SYSTEM_TOPIC_PREFIXES = Set.of(
"RMQ_SYS_", "SCHEDULE_TOPIC_", "%RETRY%", "%DLQ%", "CID_"
);
@@ -82,17 +79,18 @@ public class RocketMQMetadataProvider implements MetadataProvider {
"RMQ_SYS_TRACE_TOPIC", "RMQ_SYS_TRANS_OP_HALF_TOPIC"
);
- private final DefaultMQAdminExt adminExt;
+ private final MqAdminExtFactory adminFactory;
+ private final RocketMQProperties properties;
private final RmqTopicMapper topicMapper;
private final RmqGroupMapper groupMapper;
- @Autowired
- public RocketMQMetadataProvider(@Autowired(required = false) DefaultMQAdminExt adminExt,
- RmqTopicMapper topicMapper,
- RmqGroupMapper groupMapper) {
- this.adminExt = adminExt;
- this.topicMapper = topicMapper;
- this.groupMapper = groupMapper;
+ /** Whether a default NameServer is configured and live queries are therefore possible. */
+ private boolean hasAdmin() {
+ return StringUtils.hasText(properties.getNamesrvAddr());
+ }
+
+ private <T> T adminExecute(MqAdminExtFactory.AdminAction<T> action) {
+ return adminFactory.execute(properties.getNamesrvAddr(), null, action);
}
@Override
@@ -173,7 +171,7 @@ public class RocketMQMetadataProvider implements MetadataProvider {
vo.setCreatedAt(entity.getCreatedAt());
vo.setUpdatedAt(entity.getUpdatedAt());
- if (adminExt != null) {
+ if (hasAdmin()) {
enrichGroupWithConnectionInfo(vo, entity.getName());
}
result.add(vo);
@@ -195,120 +193,124 @@ public class RocketMQMetadataProvider implements MetadataProvider {
@Override
public List<BrokerRouteVO> getTopicRoutes(String name) {
- if (adminExt == null) {
+ if (!hasAdmin()) {
return Collections.emptyList();
}
- try {
- TopicRouteData routeData = adminExt.examineTopicRouteInfo(name);
- if (routeData == null) {
- return Collections.emptyList();
- }
+ return adminExecute(admin -> {
+ try {
+ TopicRouteData routeData = admin.examineTopicRouteInfo(name);
+ if (routeData == null) {
+ return Collections.emptyList();
+ }
- Map<String, BrokerData> brokerDataMap = new HashMap<>();
- if (routeData.getBrokerDatas() != null) {
- for (BrokerData bd : routeData.getBrokerDatas()) {
- brokerDataMap.put(bd.getBrokerName(), bd);
+ Map<String, BrokerData> brokerDataMap = new HashMap<>();
+ if (routeData.getBrokerDatas() != null) {
+ for (BrokerData bd : routeData.getBrokerDatas()) {
+ brokerDataMap.put(bd.getBrokerName(), bd);
+ }
}
- }
- List<BrokerRouteVO> routes = new ArrayList<>();
- if (routeData.getQueueDatas() != null) {
- for (QueueData qd : routeData.getQueueDatas()) {
- BrokerData bd = brokerDataMap.get(qd.getBrokerName());
- String brokerAddr = "";
- if (bd != null && bd.getBrokerAddrs() != null && !bd.getBrokerAddrs().isEmpty()) {
- brokerAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
- if (brokerAddr == null) {
- brokerAddr = bd.getBrokerAddrs().values().iterator().next();
+ List<BrokerRouteVO> routes = new ArrayList<>();
+ if (routeData.getQueueDatas() != null) {
+ for (QueueData qd : routeData.getQueueDatas()) {
+ BrokerData bd = brokerDataMap.get(qd.getBrokerName());
+ String brokerAddr = "";
+ if (bd != null && bd.getBrokerAddrs() != null && !bd.getBrokerAddrs().isEmpty()) {
+ brokerAddr = bd.getBrokerAddrs().get(MixAll.MASTER_ID);
+ if (brokerAddr == null) {
+ brokerAddr = bd.getBrokerAddrs().values().iterator().next();
+ }
}
- }
- routes.add(BrokerRouteVO.builder()
- .brokerName(qd.getBrokerName())
- .brokerAddr(brokerAddr)
- .writeQueues(qd.getWriteQueueNums())
- .readQueues(qd.getReadQueueNums())
- .perm(mapPerm(qd.getPerm()))
- .build());
+ routes.add(BrokerRouteVO.builder()
+ .brokerName(qd.getBrokerName())
+ .brokerAddr(brokerAddr)
+ .writeQueues(qd.getWriteQueueNums())
+ .readQueues(qd.getReadQueueNums())
+ .perm(mapPerm(qd.getPerm()))
+ .build());
+ }
}
+ return routes;
+ } catch (Exception e) {
+ log.warn("Failed to get routes for topic {}: {}", name, e.getMessage());
+ return Collections.emptyList();
}
- return routes;
- } catch (Exception e) {
- log.warn("Failed to get routes for topic {}: {}", name, e.getMessage());
- return Collections.emptyList();
- }
+ });
}
@Override
public List<TopicConsumerVO> getTopicConsumers(String name) {
- if (adminExt == null) {
+ if (!hasAdmin()) {
return Collections.emptyList();
}
- try {
- // Ask the broker who consumes this topic instead of scanning every subscription
- // group, which floods the result with system groups.
- GroupList groupList = adminExt.queryTopicConsumeByWho(name);
- Set<String> subscribingGroups = new HashSet<>();
- if (groupList != null && groupList.getGroupList() != null) {
- for (String group : groupList.getGroupList()) {
- if (!isSystemConsumerGroup(group)) {
- subscribingGroups.add(group);
+ return adminExecute(admin -> {
+ try {
+ // Ask the broker who consumes this topic instead of scanning every subscription
+ // group, which floods the result with system groups.
+ GroupList groupList = admin.queryTopicConsumeByWho(name);
+ Set<String> subscribingGroups = new HashSet<>();
+ if (groupList != null && groupList.getGroupList() != null) {
+ for (String group : groupList.getGroupList()) {
+ if (!isSystemConsumerGroup(group)) {
+ subscribingGroups.add(group);
+ }
}
}
- }
- List<TopicConsumerVO> consumers = new ArrayList<>();
- for (String group : subscribingGroups) {
- try {
- ConsumeStats stats = adminExt.examineConsumeStats(group, name);
- long diffTotal = 0;
- double consumeTps = 0;
- if (stats != null && stats.getOffsetTable() != null) {
- for (Map.Entry<MessageQueue, OffsetWrapper> entry : stats.getOffsetTable().entrySet()) {
- OffsetWrapper ow = entry.getValue();
- diffTotal += Math.max(0, ow.getBrokerOffset() - ow.getConsumerOffset());
+ List<TopicConsumerVO> consumers = new ArrayList<>();
+ for (String group : subscribingGroups) {
+ try {
+ ConsumeStats stats = admin.examineConsumeStats(group, name);
+ long diffTotal = 0;
+ double consumeTps = 0;
+ if (stats != null && stats.getOffsetTable() != null) {
+ for (Map.Entry<MessageQueue, OffsetWrapper> entry : stats.getOffsetTable().entrySet()) {
+ OffsetWrapper ow = entry.getValue();
+ diffTotal += Math.max(0, ow.getBrokerOffset() - ow.getConsumerOffset());
+ }
+ consumeTps = stats.getConsumeTps();
}
- consumeTps = stats.getConsumeTps();
- }
- ConsumeType consumeType = ConsumeType.CLUSTERING;
- String messageModel = "CLUSTERING";
- try {
- ConsumerConnection conn = adminExt.examineConsumerConnectionInfo(group);
- if (conn != null && conn.getMessageModel() != null) {
- messageModel = conn.getMessageModel().name();
- consumeType = parseConsumeType(messageModel);
+ ConsumeType consumeType = ConsumeType.CLUSTERING;
+ String messageModel = "CLUSTERING";
+ try {
+ ConsumerConnection conn = admin.examineConsumerConnectionInfo(group);
+ if (conn != null && conn.getMessageModel() != null) {
+ messageModel = conn.getMessageModel().name();
+ consumeType = parseConsumeType(messageModel);
+ }
+ } catch (Exception ignored) {
+ // group may be offline
}
+
+ consumers.add(TopicConsumerVO.builder()
+ .group(group)
+ .consumeType(consumeType)
+ .messageModel(messageModel)
+ .consumeTps(consumeTps)
+ .diffTotal(diffTotal)
+ .build());
} catch (Exception ignored) {
- // group may be offline
+ // stats unavailable for this group, still list it below without numbers
+ consumers.add(TopicConsumerVO.builder()
+ .group(group)
+ .consumeType(ConsumeType.CLUSTERING)
+ .messageModel("CLUSTERING")
+ .consumeTps(0)
+ .diffTotal(0)
+ .build());
}
-
- consumers.add(TopicConsumerVO.builder()
- .group(group)
- .consumeType(consumeType)
- .messageModel(messageModel)
- .consumeTps(consumeTps)
- .diffTotal(diffTotal)
- .build());
- } catch (Exception ignored) {
- // stats unavailable for this group, still list it below without numbers
- consumers.add(TopicConsumerVO.builder()
- .group(group)
- .consumeType(ConsumeType.CLUSTERING)
- .messageModel("CLUSTERING")
- .consumeTps(0)
- .diffTotal(0)
- .build());
}
+ consumers.sort((a, b) -> a.getGroup().compareToIgnoreCase(b.getGroup()));
+ return consumers;
+ } catch (Exception e) {
+ log.warn("Failed to get consumers for topic {}: {}", name, e.getMessage());
+ return Collections.emptyList();
}
- consumers.sort((a, b) -> a.getGroup().compareToIgnoreCase(b.getGroup()));
- return consumers;
- } catch (Exception e) {
- log.warn("Failed to get consumers for topic {}: {}", name, e.getMessage());
- return Collections.emptyList();
- }
+ });
}
private boolean isSystemConsumerGroup(String group) {
@@ -325,105 +327,80 @@ public class RocketMQMetadataProvider implements MetadataProvider {
@Override
public List<QueueProgressVO> getGroupProgress(String name) {
- if (adminExt == null) {
+ if (!hasAdmin()) {
return Collections.emptyList();
}
- try {
- ConsumeStats stats = adminExt.examineConsumeStats(name);
- if (stats == null || stats.getOffsetTable() == null) {
- return Collections.emptyList();
- }
+ return adminExecute(admin -> {
+ try {
+ ConsumeStats stats = admin.examineConsumeStats(name);
+ if (stats == null || stats.getOffsetTable() == null) {
+ return Collections.emptyList();
+ }
- List<QueueProgressVO> progress = new ArrayList<>();
- for (Map.Entry<MessageQueue, OffsetWrapper> entry : stats.getOffsetTable().entrySet()) {
- MessageQueue mq = entry.getKey();
- OffsetWrapper ow = entry.getValue();
- long diff = Math.max(0, ow.getBrokerOffset() - ow.getConsumerOffset());
-
- progress.add(QueueProgressVO.builder()
- .broker(mq.getBrokerName())
- .queueId(mq.getQueueId())
- .brokerOffset(ow.getBrokerOffset())
- .consumerOffset(ow.getConsumerOffset())
- .diffTotal(diff)
- .build());
- }
+ List<QueueProgressVO> progress = new ArrayList<>();
+ for (Map.Entry<MessageQueue, OffsetWrapper> entry : stats.getOffsetTable().entrySet()) {
+ MessageQueue mq = entry.getKey();
+ OffsetWrapper ow = entry.getValue();
+ long diff = Math.max(0, ow.getBrokerOffset() - ow.getConsumerOffset());
+
+ progress.add(QueueProgressVO.builder()
+ .broker(mq.getBrokerName())
+ .queueId(mq.getQueueId())
+ .brokerOffset(ow.getBrokerOffset())
+ .consumerOffset(ow.getConsumerOffset())
+ .diffTotal(diff)
+ .build());
+ }
- progress.sort((a, b) -> {
- int cmp = a.getBroker().compareToIgnoreCase(b.getBroker());
- return cmp != 0 ? cmp : Integer.compare(a.getQueueId(), b.getQueueId());
- });
- return progress;
- } catch (Exception e) {
- log.warn("Failed to get progress for group {}: {}", name, e.getMessage());
- return Collections.emptyList();
- }
+ progress.sort((a, b) -> {
+ int cmp = a.getBroker().compareToIgnoreCase(b.getBroker());
+ return cmp != 0 ? cmp : Integer.compare(a.getQueueId(), b.getQueueId());
+ });
+ return progress;
+ } catch (Exception e) {
+ log.warn("Failed to get progress for group {}: {}", name, e.getMessage());
+ return Collections.emptyList();
+ }
+ });
}
@Override
public List<SubscriptionEntryVO> getGroupSubscriptions(String name) {
- if (adminExt == null) {
+ if (!hasAdmin()) {
return Collections.emptyList();
}
- try {
- ConsumerConnection conn = adminExt.examineConsumerConnectionInfo(name);
- if (conn == null || conn.getSubscriptionTable() == null) {
- return Collections.emptyList();
- }
+ return adminExecute(admin -> {
+ try {
+ ConsumerConnection conn = admin.examineConsumerConnectionInfo(name);
+ if (conn == null || conn.getSubscriptionTable() == null) {
+ return Collections.emptyList();
+ }
- List<SubscriptionEntryVO> subscriptions = new ArrayList<>();
- for (Map.Entry<String, SubscriptionData> entry : conn.getSubscriptionTable().entrySet()) {
- SubscriptionData sd = entry.getValue();
- subscriptions.add(SubscriptionEntryVO.builder()
- .topic(sd.getTopic())
- .expression(sd.getSubString())
- .type(sd.getExpressionType())
- .filterMode(filterMode(sd.getExpressionType()))
- .build());
+ List<SubscriptionEntryVO> subscriptions = new ArrayList<>();
+ for (Map.Entry<String, SubscriptionData> entry : conn.getSubscriptionTable().entrySet()) {
+ SubscriptionData sd = entry.getValue();
+ subscriptions.add(SubscriptionEntryVO.builder()
+ .topic(sd.getTopic())
+ .expression(sd.getSubString())
+ .type(sd.getExpressionType())
+ .filterMode(filterMode(sd.getExpressionType()))
+ .build());
+ }
+ return subscriptions;
+ } catch (Exception e) {
+ log.warn("Failed to get subscriptions for group {}: {}", name, e.getMessage());
+ return Collections.emptyList();
}
- return subscriptions;
- } catch (Exception e) {
- log.warn("Failed to get subscriptions for group {}: {}", name, e.getMessage());
- return Collections.emptyList();
- }
+ });
}
// ── Helper methods ──────────────────────────────────────────────────
- private TopicVO buildTopicVO(String topicName) {
- try {
- TopicRouteData routeData = adminExt.examineTopicRouteInfo(topicName);
- if (routeData == null || routeData.getQueueDatas() == null || routeData.getQueueDatas().isEmpty()) {
- // Topic exists in nameserver but has no route data
- TopicVO vo = new TopicVO();
- vo.setId(topicName);
- vo.setName(topicName);
- return vo;
- }
-
- QueueData firstQd = routeData.getQueueDatas().get(0);
- TopicVO vo = new TopicVO();
- vo.setId(topicName);
- vo.setName(topicName);
- vo.setWriteQueues(firstQd.getWriteQueueNums());
- vo.setReadQueues(firstQd.getReadQueueNums());
- vo.setPerm(mapPerm(firstQd.getPerm()));
- vo.setType(inferTopicType(topicName));
- return vo;
- } catch (Exception e) {
- log.debug("Failed to get route for topic {}: {}", topicName, e.getMessage());
- TopicVO vo = new TopicVO();
- vo.setId(topicName);
- vo.setName(topicName);
- return vo;
- }
- }
-
private void enrichGroupWithConnectionInfo(ConsumerGroupVO vo, String groupName) {
try {
- ConsumerConnection conn = adminExt.examineConsumerConnectionInfo(groupName);
+ ConsumerConnection conn = adminExecute(admin -> admin.examineConsumerConnectionInfo(groupName));
if (conn != null) {
if (conn.getConnectionSet() != null) {
vo.setOnlineInstances(conn.getConnectionSet().size());
@@ -438,7 +415,7 @@ public class RocketMQMetadataProvider implements MetadataProvider {
// Try to get lag info
try {
- ConsumeStats stats = adminExt.examineConsumeStats(groupName);
+ ConsumeStats stats = adminExecute(admin -> admin.examineConsumeStats(groupName));
if (stats != null && stats.getOffsetTable() != null) {
long totalLag = 0;
for (OffsetWrapper ow : stats.getOffsetTable().values()) {
@@ -461,18 +438,6 @@ public class RocketMQMetadataProvider implements MetadataProvider {
return "TAG";
}
- private Set<String> getBrokerNames() {
- Set<String> names = new HashSet<>();
- try {
- ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
- if (clusterInfo != null && clusterInfo.getBrokerAddrTable() != null) {
- names.addAll(clusterInfo.getBrokerAddrTable().keySet());
- }
- } catch (Exception ignored) {
- }
- return names;
- }
-
private boolean isSystemTopic(String topicName, Set<String> brokerNames) {
if (SYSTEM_TOPICS.contains(topicName)) {
return true;
@@ -497,17 +462,4 @@ public class RocketMQMetadataProvider implements MetadataProvider {
}
return TopicPerm.RW;
}
-
- private org.apache.rocketmq.studio.common.domain.enums.TopicType inferTopicType(String topicName) {
- if (topicName.contains("TRANS") || topicName.contains("trans")) {
- return org.apache.rocketmq.studio.common.domain.enums.TopicType.TRANSACTION;
- }
- if (topicName.contains("DELAY") || topicName.contains("delay") || topicName.contains("SCHEDULE")) {
- return org.apache.rocketmq.studio.common.domain.enums.TopicType.DELAY;
- }
- if (topicName.contains("FIFO") || topicName.contains("fifo") || topicName.contains("ORDER")) {
- return org.apache.rocketmq.studio.common.domain.enums.TopicType.FIFO;
- }
- return org.apache.rocketmq.studio.common.domain.enums.TopicType.NORMAL;
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQProperties.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQProperties.java
similarity index 90%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQProperties.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQProperties.java
index 5c4bbaac..78aafb5d 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQProperties.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/RocketMQProperties.java
@@ -14,12 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
@Data
+@Component
@ConfigurationProperties(prefix = "studio.rocketmq")
public class RocketMQProperties {
private String namesrvAddr;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/ShortLivedClientName.java b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ShortLivedClientName.java
similarity index 95%
rename from server/src/main/java/org/apache/rocketmq/studio/rocketmq/ShortLivedClientName.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/apache/ShortLivedClientName.java
index b2ee385d..3259856d 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/ShortLivedClientName.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/apache/ShortLivedClientName.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.rocketmq;
+package org.apache.rocketmq.studio.provider.apache;
import java.util.UUID;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialController.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialController.java
similarity index 90%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialController.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialController.java
index 540cf116..40f99a74 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialController.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialController.java
@@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.provider.credential;
import jakarta.validation.Valid;
+import org.apache.rocketmq.studio.common.domain.DeleteRequestDTO;
import org.apache.rocketmq.studio.common.domain.Result;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.springframework.web.bind.annotation.GetMapping;
@@ -25,19 +26,17 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import lombok.RequiredArgsConstructor;
import java.util.List;
+@RequiredArgsConstructor
@RestController
@RequestMapping("/api/cloud-credentials")
public class CloudCredentialController {
private final CloudCredentialService credentialService;
- public CloudCredentialController(CloudCredentialService credentialService) {
- this.credentialService = credentialService;
- }
-
@GetMapping
public Result<List<CloudCredentialVO>> listCredentials() {
return Result.ok(credentialService.listMasked());
@@ -62,7 +61,7 @@ public class CloudCredentialController {
}
@PostMapping("/delete")
- public Result<Void> deleteCredential(@Valid @RequestBody CloudCredentialDeleteRequestDTO request) {
+ public Result<Void> deleteCredential(@Valid @RequestBody DeleteRequestDTO request) {
credentialService.delete(request.getId());
return Result.ok();
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialRepository.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialRepository.java
similarity index 95%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialRepository.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialRepository.java
index 94e5d4fd..b6f12ae2 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialRepository.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.provider.credential;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialService.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialService.java
similarity index 77%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialService.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialService.java
index c1418344..503b9385 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialService.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialService.java
@@ -14,36 +14,29 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.provider.credential;
+
+import org.springframework.util.StringUtils;
import org.apache.rocketmq.studio.common.exception.BusinessException;
+import org.apache.rocketmq.studio.common.util.CredentialUtils;
import org.apache.rocketmq.studio.instance.InstanceRepository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
+@Slf4j
+@RequiredArgsConstructor
@Service
public class CloudCredentialService {
- private static final Logger log = LoggerFactory.getLogger(CloudCredentialService.class);
-
- private static final int VISIBLE_CREDENTIAL_CHARS = 4;
- private static final int MIN_PARTIALLY_MASKED_CREDENTIAL_CHARS = 17;
- private static final String CREDENTIAL_MASK = "****";
-
private final CloudCredentialRepository credentialRepository;
private final InstanceRepository instanceRepository;
- public CloudCredentialService(CloudCredentialRepository credentialRepository,
- InstanceRepository instanceRepository) {
- this.credentialRepository = credentialRepository;
- this.instanceRepository = instanceRepository;
- }
-
public List<CloudCredentialVO> listMasked() {
log.info("Listing cloud credentials (masked)");
return credentialRepository.findAll().stream()
@@ -55,20 +48,20 @@ public class CloudCredentialService {
if (credential == null) {
throw new BusinessException(400, "Cloud credential request is required");
}
- if (isBlank(credential.getName())) {
+ if (!StringUtils.hasText(credential.getName())) {
throw new BusinessException(400, "Cloud credential name is required");
}
if (credential.getVendor() == null || credential.getVendor() == org.apache.rocketmq.studio.common.domain.enums.InstanceVendor.APACHE) {
throw new BusinessException(400, "Cloud credential vendor must be ALIYUN or TENCENT");
}
- if (isBlank(credential.getAccessKey()) || isBlank(credential.getSecretKey())) {
+ if (!StringUtils.hasText(credential.getAccessKey()) || !StringUtils.hasText(credential.getSecretKey())) {
throw new BusinessException(400, "Cloud credential accessKey and secretKey are required");
}
credentialRepository.findByVendorAndAccessKey(credential.getVendor(), credential.getAccessKey())
.ifPresent(existing -> {
throw new BusinessException(400,
"Cloud credential already exists for vendor " + credential.getVendor()
- + " and accessKey " + maskCredential(credential.getAccessKey()));
+ + " and accessKey " + CredentialUtils.mask(credential.getAccessKey()));
});
log.info("Creating cloud credential name={}, vendor={}", credential.getName(), credential.getVendor());
credential.setId(UUID.randomUUID().toString());
@@ -78,7 +71,7 @@ public class CloudCredentialService {
}
public CloudCredentialVO update(UpdateCloudCredentialDTO request) {
- if (request == null || isBlank(request.getId())) {
+ if (request == null || !StringUtils.hasText(request.getId())) {
throw new BusinessException(400, "Cloud credential id is required");
}
log.info("Updating cloud credential id={}", request.getId());
@@ -101,7 +94,7 @@ public class CloudCredentialService {
}
public void delete(String id) {
- if (isBlank(id)) {
+ if (!StringUtils.hasText(id)) {
throw new BusinessException(400, "Cloud credential id is required");
}
log.info("Deleting cloud credential id={}", id);
@@ -114,7 +107,7 @@ public class CloudCredentialService {
}
public CloudCredentialVO reveal(String id) {
- if (isBlank(id)) {
+ if (!StringUtils.hasText(id)) {
throw new BusinessException(400, "Cloud credential id is required");
}
return credentialRepository.findById(id)
@@ -126,24 +119,11 @@ public class CloudCredentialService {
masked.setId(credential.getId());
masked.setName(credential.getName());
masked.setVendor(credential.getVendor());
- masked.setAccessKey(maskCredential(credential.getAccessKey()));
+ masked.setAccessKey(CredentialUtils.mask(credential.getAccessKey()));
masked.setSecretKey(null);
masked.setRemark(credential.getRemark());
masked.setCreatedAt(credential.getCreatedAt());
masked.setUpdatedAt(credential.getUpdatedAt());
return masked;
}
-
- static String maskCredential(String value) {
- if (value == null || value.length() < MIN_PARTIALLY_MASKED_CREDENTIAL_CHARS) {
- return CREDENTIAL_MASK;
- }
- return value.substring(0, VISIBLE_CREDENTIAL_CHARS)
- + CREDENTIAL_MASK
- + value.substring(value.length() - VISIBLE_CREDENTIAL_CHARS);
- }
-
- private static boolean isBlank(String value) {
- return value == null || value.isBlank();
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NamespaceVO.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialVO.java
similarity index 74%
rename from server/src/main/java/org/apache/rocketmq/studio/instance/topic/NamespaceVO.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialVO.java
index 56a67154..98133b49 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/topic/NamespaceVO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CloudCredentialVO.java
@@ -14,16 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package org.apache.rocketmq.studio.instance.topic;
+package org.apache.rocketmq.studio.provider.credential;
import org.apache.rocketmq.studio.common.domain.BaseEntity;
+import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import lombok.ToString;
@Data
@EqualsAndHashCode(callSuper = true)
-public class NamespaceVO extends BaseEntity {
+public class CloudCredentialVO extends BaseEntity {
+
private String name;
- private String clusterId;
+ private InstanceVendor vendor;
+ private String accessKey;
+ @ToString.Exclude
+ private String secretKey;
+ private String remark;
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CreateCloudCredentialDTO.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CreateCloudCredentialDTO.java
similarity index 71%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CreateCloudCredentialDTO.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/CreateCloudCredentialDTO.java
index 79856bb8..92ad4ac4 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CreateCloudCredentialDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/CreateCloudCredentialDTO.java
@@ -14,11 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.provider.credential;
import jakarta.validation.constraints.NotBlank;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
+import lombok.Data;
+@Data
public class CreateCloudCredentialDTO {
@NotBlank(message = "credential name is required")
@@ -35,46 +37,6 @@ public class CreateCloudCredentialDTO {
private String remark;
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getVendor() {
- return vendor;
- }
-
- public void setVendor(String vendor) {
- this.vendor = vendor;
- }
-
- public String getAccessKey() {
- return accessKey;
- }
-
- public void setAccessKey(String accessKey) {
- this.accessKey = accessKey;
- }
-
- public String getSecretKey() {
- return secretKey;
- }
-
- public void setSecretKey(String secretKey) {
- this.secretKey = secretKey;
- }
-
- public String getRemark() {
- return remark;
- }
-
- public void setRemark(String remark) {
- this.remark = remark;
- }
-
public CloudCredentialVO toCloudCredentialVO() {
CloudCredentialVO vo = new CloudCredentialVO();
vo.setName(name);
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/MybatisPlusCloudCredentialRepository.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/MybatisPlusCloudCredentialRepository.java
similarity index 82%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/MybatisPlusCloudCredentialRepository.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/MybatisPlusCloudCredentialRepository.java
index c83b7352..137131c0 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/MybatisPlusCloudCredentialRepository.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/MybatisPlusCloudCredentialRepository.java
@@ -14,17 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.provider.credential;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
+import org.apache.rocketmq.studio.common.util.CredentialUtils;
import org.apache.rocketmq.studio.persistence.entity.RmqCloudCredential;
import org.apache.rocketmq.studio.persistence.mapper.RmqCloudCredentialMapper;
import org.springframework.stereotype.Repository;
+import lombok.RequiredArgsConstructor;
-import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
-import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -33,15 +33,12 @@ import java.util.stream.Collectors;
* MySQL-backed cloud credential repository. Secret keys are stored base64-encoded in
* {@code rmq_cloud_credential.secret_key} and decoded when read; plain text is never persisted.
*/
+@RequiredArgsConstructor
@Repository
public class MybatisPlusCloudCredentialRepository implements CloudCredentialRepository {
private final RmqCloudCredentialMapper credentialMapper;
- public MybatisPlusCloudCredentialRepository(RmqCloudCredentialMapper credentialMapper) {
- this.credentialMapper = credentialMapper;
- }
-
@Override
public List<CloudCredentialVO> findAll() {
return credentialMapper.selectList(
@@ -90,7 +87,7 @@ public class MybatisPlusCloudCredentialRepository implements CloudCredentialRepo
vo.setName(entity.getName());
vo.setVendor(parseVendor(entity.getVendor()));
vo.setAccessKey(entity.getAccessKey());
- vo.setSecretKey(decodeBase64(entity.getSecretKey()));
+ vo.setSecretKey(CredentialUtils.decodeBase64(entity.getSecretKey()));
vo.setRemark(entity.getRemark());
vo.setCreatedAt(entity.getCreatedAt());
vo.setUpdatedAt(entity.getUpdatedAt());
@@ -103,7 +100,7 @@ public class MybatisPlusCloudCredentialRepository implements CloudCredentialRepo
entity.setName(vo.getName());
entity.setVendor(vo.getVendor() == null ? null : vo.getVendor().name());
entity.setAccessKey(vo.getAccessKey());
- entity.setSecretKey(encodeBase64(vo.getSecretKey()));
+ entity.setSecretKey(CredentialUtils.encodeBase64(vo.getSecretKey()));
entity.setRemark(vo.getRemark());
entity.setCreatedAt(vo.getCreatedAt());
entity.setUpdatedAt(vo.getUpdatedAt() == null ? LocalDateTime.now() : vo.getUpdatedAt());
@@ -117,23 +114,4 @@ public class MybatisPlusCloudCredentialRepository implements CloudCredentialRepo
return null;
}
}
-
- static String encodeBase64(String plainText) {
- if (plainText == null) {
- return null;
- }
- return Base64.getEncoder().encodeToString(plainText.getBytes(StandardCharsets.UTF_8));
- }
-
- static String decodeBase64(String stored) {
- if (stored == null) {
- return null;
- }
- try {
- return new String(Base64.getDecoder().decode(stored), StandardCharsets.UTF_8);
- } catch (IllegalArgumentException ex) {
- // tolerate legacy values that were stored without encoding
- return stored;
- }
- }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialDeleteRequestDTO.java b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/UpdateCloudCredentialDTO.java
similarity index 81%
rename from server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialDeleteRequestDTO.java
rename to server/src/main/java/org/apache/rocketmq/studio/provider/credential/UpdateCloudCredentialDTO.java
index d4513327..6219c5bc 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/cloud/credential/CloudCredentialDeleteRequestDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/credential/UpdateCloudCredentialDTO.java
@@ -14,20 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.cloud.credential;
+package org.apache.rocketmq.studio.provider.credential;
import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
-public class CloudCredentialDeleteRequestDTO {
+@Data
+public class UpdateCloudCredentialDTO {
@NotBlank(message = "credential id is required")
private String id;
- public String getId() {
- return id;
- }
+ private String name;
- public void setId(String id) {
- this.id = id;
- }
+ private String secretKey;
+
+ private String remark;
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java b/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
index ca4df5f4..62b9f8c0 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/provider/tencent/TencentInstanceProvider.java
@@ -42,6 +42,16 @@ public class TencentInstanceProvider implements InstanceProvider {
return InstanceVendor.TENCENT;
}
+ @Override
+ public int countTopics(String instanceId) {
+ throw new UnsupportedOperationException(NOT_IMPLEMENTED);
+ }
+
+ @Override
+ public int countGroups(String instanceId) {
+ throw new UnsupportedOperationException(NOT_IMPLEMENTED);
+ }
+
@Override
public List<TopicVO> listTopics(String instanceId, String type, String search) {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQAdminClientImpl.java b/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQAdminClientImpl.java
deleted file mode 100644
index ceec6bf6..00000000
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQAdminClientImpl.java
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.rocketmq.studio.rocketmq;
-
-import org.apache.rocketmq.client.exception.MQClientException;
-import org.apache.rocketmq.client.producer.DefaultMQProducer;
-import org.apache.rocketmq.client.producer.SendResult;
-import org.apache.rocketmq.common.TopicConfig;
-import org.apache.rocketmq.common.message.Message;
-import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
-import org.apache.rocketmq.remoting.protocol.ResponseCode;
-import org.apache.rocketmq.remoting.protocol.route.BrokerData;
-import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
-import org.apache.rocketmq.studio.common.exception.BusinessException;
-import org.apache.rocketmq.studio.common.domain.enums.TopicPerm;
-import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
-import org.apache.rocketmq.studio.instance.topic.AdminClient;
-import org.apache.rocketmq.studio.instance.topic.SendMessageDTO;
-import org.apache.rocketmq.studio.instance.topic.SendMessageVO;
-import org.apache.rocketmq.studio.instance.topic.TopicVO;
-import org.apache.rocketmq.studio.ops.audit.AuditService;
-import org.apache.rocketmq.studio.persistence.entity.RmqGroup;
-import org.apache.rocketmq.studio.persistence.entity.RmqTopic;
-import org.apache.rocketmq.studio.persistence.mapper.RmqGroupMapper;
-import org.apache.rocketmq.studio.persistence.mapper.RmqTopicMapper;
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Primary;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-
-import java.nio.charset.StandardCharsets;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Real AdminClient implementation backed by DefaultMQAdminExt.
- * Provides topic CRUD, message sending, consumer group CRUD, and offset reset.
- */
-@Service
-@Primary
-public class RocketMQAdminClientImpl implements AdminClient {
-
- private static final Logger log = LoggerFactory.getLogger(RocketMQAdminClientImpl.class);
- private static final String MESSAGE_SENDER_GROUP_PREFIX = "studio-msg-sender";
-
- private final DefaultMQAdminExt adminExt;
- private final RocketMQProperties properties;
- private final RmqTopicMapper topicMapper;
- private final RmqGroupMapper groupMapper;
- private final AuditService auditService;
-
- @Autowired
- public RocketMQAdminClientImpl(
- @Autowired(required = false) DefaultMQAdminExt adminExt,
- RocketMQProperties properties,
- RmqTopicMapper topicMapper,
- RmqGroupMapper groupMapper,
- AuditService auditService) {
- this.adminExt = adminExt;
- this.properties = properties;
- this.topicMapper = topicMapper;
- this.groupMapper = groupMapper;
- this.auditService = auditService;
- }
-
- @Override
- public TopicVO getTopic(String name) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
- try {
- var routeData = adminExt.examineTopicRouteInfo(name);
- if (routeData == null || routeData.getQueueDatas() == null || routeData.getQueueDatas().isEmpty()) {
- throw new BusinessException(404, "Topic not found: " + name);
- }
- var qd = routeData.getQueueDatas().get(0);
- TopicVO vo = new TopicVO();
- vo.setId(name);
- vo.setName(name);
- vo.setWriteQueues(qd.getWriteQueueNums());
- vo.setReadQueues(qd.getReadQueueNums());
- return vo;
- } catch (BusinessException e) {
- throw e;
- } catch (Exception e) {
- throw new BusinessException(500, "Failed to get topic: " + e.getMessage());
- }
- }
-
- @Override
- public ConsumerGroupVO getConsumerGroup(String name) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
- ConsumerGroupVO vo = new ConsumerGroupVO();
- vo.setId(name);
- vo.setName(name);
- try {
- var conn = adminExt.examineConsumerConnectionInfo(name);
- if (conn != null) {
- if (conn.getConnectionSet() != null) {
- vo.setOnlineInstances(conn.getConnectionSet().size());
- }
- if (conn.getSubscriptionTable() != null) {
- vo.setSubscribedTopics(new ArrayList<>(conn.getSubscriptionTable().keySet()));
- }
- }
- } catch (MQClientException exception) {
- if (exception.getResponseCode() == ResponseCode.CONSUMER_NOT_ONLINE) {
- log.debug("Consumer group {} is offline", name);
- return vo;
- }
- throw new BusinessException(502, "Failed to get consumer group: " + exception.getMessage());
- } catch (Exception exception) {
- throw new BusinessException(502, "Failed to get consumer group: " + exception.getMessage());
- }
- return vo;
- }
-
- @Override
- public TopicVO createTopic(TopicVO topic) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- String topicName = topic.getName();
- int writeQueues = topic.getWriteQueues() > 0 ? topic.getWriteQueues() : 8;
- int readQueues = topic.getReadQueues() > 0 ? topic.getReadQueues() : 8;
-
- try {
- String clusterName = getClusterName();
- // Match on the (cluster_id, name) key: the same topic name can exist in several
- // clusters, and a name-only lookup would blow up with TooManyResultsException.
- RmqTopic existing = topicMapper.selectOne(
- new LambdaQueryWrapper<RmqTopic>()
- .eq(RmqTopic::getClusterId, clusterName)
- .eq(RmqTopic::getName, topicName));
- TopicPerm effectivePerm = topic.getPerm() != null
- ? topic.getPerm()
- : existing == null ? TopicPerm.RW : fromRocketMQPerm(existing.getPerm());
- Set<String> brokerAddrs = getAllMasterBrokerAddrs();
- if (brokerAddrs.isEmpty()) {
- throw new BusinessException(500, "No broker available to create topic");
- }
-
- TopicConfig topicConfig = new TopicConfig();
- topicConfig.setTopicName(topicName);
- topicConfig.setWriteQueueNums(writeQueues);
- topicConfig.setReadQueueNums(readQueues);
- topicConfig.setPerm(toRocketMQPerm(effectivePerm));
-
- for (String addr : brokerAddrs) {
- adminExt.createAndUpdateTopicConfig(addr, topicConfig);
- }
-
- // Persist to DB. Re-creating a topic that already has a record (for example when
- // rebuilding a broker route from the console) must update it instead of failing on
- // the unique (cluster_id, name) key.
- RmqTopic entity = topicMapper.selectOne(new LambdaQueryWrapper<RmqTopic>()
- .eq(RmqTopic::getClusterId, clusterName)
- .eq(RmqTopic::getName, topicName));
- boolean isNew = entity == null;
- if (isNew) {
- entity = new RmqTopic();
- entity.setName(topicName);
- entity.setClusterId(clusterName);
- entity.setCreatedAt(LocalDateTime.now());
- }
- if (StringUtils.hasText(topic.getInstanceId())) {
- entity.setInstanceId(topic.getInstanceId());
- }
- entity.setTopicType(topic.getType() != null ? topic.getType().name() : "NORMAL");
- entity.setReadQueueNums(readQueues);
- entity.setWriteQueueNums(writeQueues);
- entity.setPerm(topicConfig.getPerm());
- if (StringUtils.hasText(topic.getRemark())) {
- entity.setRemark(topic.getRemark());
- }
- entity.setStatus("ACTIVE");
- entity.setUpdatedAt(LocalDateTime.now());
- if (isNew) {
- topicMapper.insert(entity);
- } else {
- topicMapper.updateById(entity);
- }
-
- auditService.record("CREATE_TOPIC", topicName,
- "queues=" + writeQueues + "/" + readQueues, "SUCCESS");
-
- topic.setId(topicName);
- topic.setWriteQueues(writeQueues);
- topic.setReadQueues(readQueues);
- return topic;
- } catch (BusinessException e) {
- auditService.record("CREATE_TOPIC", topicName, e.getMessage(), "FAILED");
- throw e;
- } catch (Exception e) {
- auditService.record("CREATE_TOPIC", topicName, e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to create topic: " + e.getMessage());
- }
- }
-
- @Override
- public TopicVO updateTopic(TopicVO topic) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- String topicName = topic.getName();
- int writeQueues = topic.getWriteQueues() > 0 ? topic.getWriteQueues() : 8;
- int readQueues = topic.getReadQueues() > 0 ? topic.getReadQueues() : 8;
-
- try {
- // Match on the (cluster_id, name) key to avoid ambiguity when several clusters share
- // the same topic name (a name-only lookup would throw TooManyResultsException).
- String clusterName = getClusterName();
- RmqTopic existing = topicMapper.selectOne(
- new LambdaQueryWrapper<RmqTopic>()
- .eq(RmqTopic::getClusterId, clusterName)
- .eq(RmqTopic::getName, topicName));
- TopicPerm effectivePerm = topic.getPerm() != null
- ? topic.getPerm()
- : existing == null ? TopicPerm.RW : fromRocketMQPerm(existing.getPerm());
- Set<String> brokerAddrs = getAllMasterBrokerAddrs();
- if (brokerAddrs.isEmpty()) {
- throw new BusinessException(500, "No broker available to update topic");
- }
-
- TopicConfig topicConfig = new TopicConfig();
- topicConfig.setTopicName(topicName);
- topicConfig.setWriteQueueNums(writeQueues);
- topicConfig.setReadQueueNums(readQueues);
- topicConfig.setPerm(toRocketMQPerm(effectivePerm));
-
- for (String addr : brokerAddrs) {
- adminExt.createAndUpdateTopicConfig(addr, topicConfig);
- }
-
- // Update DB record
- if (existing != null) {
- existing.setWriteQueueNums(writeQueues);
- existing.setReadQueueNums(readQueues);
- existing.setPerm(topicConfig.getPerm());
- existing.setUpdatedAt(LocalDateTime.now());
- topicMapper.updateById(existing);
- }
-
- auditService.record("UPDATE_TOPIC", topicName,
- "queues=" + writeQueues + "/" + readQueues, "SUCCESS");
-
- topic.setId(topicName);
- topic.setWriteQueues(writeQueues);
- topic.setReadQueues(readQueues);
- return topic;
- } catch (BusinessException e) {
- auditService.record("UPDATE_TOPIC", topicName, e.getMessage(), "FAILED");
- throw e;
- } catch (Exception e) {
- auditService.record("UPDATE_TOPIC", topicName, e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to update topic: " + e.getMessage());
- }
- }
-
- @Override
- public void deleteTopic(String name) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- try {
- Set<String> brokerAddrs = getAllMasterBrokerAddrs();
-
- // Delete from brokers
- if (!brokerAddrs.isEmpty()) {
- adminExt.deleteTopicInBroker(brokerAddrs, name);
- }
-
- // Delete from nameserver
- String namesrvAddr = properties.getNamesrvAddr();
- if (namesrvAddr != null && !namesrvAddr.isEmpty()) {
- Set<String> nsAddrs = new HashSet<>();
- for (String addr : namesrvAddr.split("[;,]")) {
- String trimmed = addr.trim();
- if (!trimmed.isEmpty()) {
- nsAddrs.add(trimmed);
- }
- }
- adminExt.deleteTopicInNameServer(nsAddrs, getClusterName(), name);
- }
-
- // Delete from DB
- topicMapper.delete(new LambdaQueryWrapper<RmqTopic>().eq(RmqTopic::getName, name));
-
- auditService.record("DELETE_TOPIC", name, "", "SUCCESS");
- } catch (BusinessException e) {
- auditService.record("DELETE_TOPIC", name, e.getMessage(), "FAILED");
- throw e;
- } catch (Exception e) {
- auditService.record("DELETE_TOPIC", name, e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to delete topic: " + e.getMessage());
- }
- }
-
- @Override
- public SendMessageVO sendMessage(SendMessageDTO request) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- String namesrvAddr = properties.getNamesrvAddr();
- if (namesrvAddr == null || namesrvAddr.isEmpty()) {
- throw new BusinessException(500, "Nameserver address not configured");
- }
-
- DefaultMQProducer producer = new DefaultMQProducer(nextMessageSenderGroup());
- producer.setNamesrvAddr(namesrvAddr);
- producer.setSendMsgTimeout(5000);
-
- try {
- producer.start();
-
- String topic = request.getTopic();
- String tag = request.getTag() != null ? request.getTag() : "";
- String key = request.getKey() != null ? request.getKey() : "";
- String body = request.getBody() != null ? request.getBody() : "";
-
- String fullTopic = tag.isEmpty() ? topic : topic + ":" + tag;
- Message msg = new Message(topic, tag, key, body.getBytes(StandardCharsets.UTF_8));
-
- // Add custom properties
- if (request.getProperties() != null) {
- for (Map.Entry<String, String> entry : request.getProperties().entrySet()) {
- msg.putUserProperty(entry.getKey(), entry.getValue());
- }
- }
-
- SendResult sendResult = producer.send(msg);
-
- // The message is already delivered by now; an audit write failure must not turn a
- // successful send into an error, or callers would retry and duplicate the message.
- try {
- auditService.record("SEND_MESSAGE", topic,
- "tag=" + tag + ", key=" + key + ", msgId=" + sendResult.getMsgId(), "SUCCESS");
- } catch (Exception auditFailure) {
- log.warn("Failed to record send message audit: {}", auditFailure.getMessage());
- }
-
- return SendMessageVO.builder()
- .msgId(sendResult.getMsgId())
- .sendTime(System.currentTimeMillis())
- .offsetMsgId(sendResult.getOffsetMsgId())
- .build();
- } catch (Exception e) {
- auditService.record("SEND_MESSAGE", request.getTopic(), e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to send message: " + e.getMessage());
- } finally {
- producer.shutdown();
- }
- }
-
- static String nextMessageSenderGroup() {
- return ShortLivedClientName.next(MESSAGE_SENDER_GROUP_PREFIX);
- }
-
- @Override
- public ConsumerGroupVO createConsumerGroup(ConsumerGroupVO group) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- String groupName = group.getName();
-
- try {
- Set<String> brokerAddrs = getAllMasterBrokerAddrs();
- if (brokerAddrs.isEmpty()) {
- throw new BusinessException(500, "No broker available to create consumer group");
- }
-
- SubscriptionGroupConfig config = new SubscriptionGroupConfig();
- config.setGroupName(groupName);
- config.setConsumeEnable(true);
- config.setConsumeBroadcastEnable(true);
- config.setRetryQueueNums(1);
- config.setRetryMaxTimes(group.getRetryMaxTimes() > 0 ? group.getRetryMaxTimes() : 16);
-
- for (String addr : brokerAddrs) {
- adminExt.createAndUpdateSubscriptionGroupConfig(addr, config);
- }
-
- // Persist to DB, upserting so re-creating an existing group does not violate the
- // unique (cluster_id, name) key.
- String groupClusterName = getClusterName();
- RmqGroup entity = groupMapper.selectOne(new LambdaQueryWrapper<RmqGroup>()
- .eq(RmqGroup::getClusterId, groupClusterName)
- .eq(RmqGroup::getName, groupName));
- boolean isNewGroup = entity == null;
- if (isNewGroup) {
- entity = new RmqGroup();
- entity.setName(groupName);
- entity.setClusterId(groupClusterName);
- entity.setCreatedAt(LocalDateTime.now());
- }
- if (StringUtils.hasText(group.getInstanceId())) {
- entity.setInstanceId(group.getInstanceId());
- }
- entity.setConsumeType(group.getConsumeType() != null ? group.getConsumeType().name() : "CLUSTERING");
- entity.setMessageModel(group.getSubscriptionMode() != null ? group.getSubscriptionMode().name() : "Push");
- entity.setMaxRetry(config.getRetryMaxTimes());
- entity.setStatus("ACTIVE");
- entity.setUpdatedAt(LocalDateTime.now());
- if (isNewGroup) {
- groupMapper.insert(entity);
- } else {
- groupMapper.updateById(entity);
- }
-
- auditService.record("CREATE_GROUP", groupName,
- "retryMaxTimes=" + config.getRetryMaxTimes(), "SUCCESS");
-
- group.setId(groupName);
- return group;
- } catch (BusinessException e) {
- auditService.record("CREATE_GROUP", groupName, e.getMessage(), "FAILED");
- throw e;
- } catch (Exception e) {
- auditService.record("CREATE_GROUP", groupName, e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to create consumer group: " + e.getMessage());
- }
- }
-
- @Override
- public void deleteConsumerGroup(String name) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- try {
- Set<String> brokerAddrs = getAllMasterBrokerAddrs();
-
- for (String addr : brokerAddrs) {
- adminExt.deleteSubscriptionGroup(addr, name, true);
- }
-
- // Delete from DB
- groupMapper.delete(new LambdaQueryWrapper<RmqGroup>().eq(RmqGroup::getName, name));
-
- auditService.record("DELETE_GROUP", name, "", "SUCCESS");
- } catch (BusinessException e) {
- auditService.record("DELETE_GROUP", name, e.getMessage(), "FAILED");
- throw e;
- } catch (Exception e) {
- auditService.record("DELETE_GROUP", name, e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to delete consumer group: " + e.getMessage());
- }
- }
-
- @Override
- public void resetOffset(String name, long timestamp, String topic) {
- if (adminExt == null) {
- throw new BusinessException(503, "RocketMQ admin not connected");
- }
-
- try {
- adminExt.resetOffsetByTimestamp(getClusterName(), topic, name, timestamp, false);
- auditService.record("RESET_OFFSET", name,
- "topic=" + topic + ", timestamp=" + timestamp, "SUCCESS");
- } catch (Exception e) {
- auditService.record("RESET_OFFSET", name, e.getMessage(), "FAILED");
- throw new BusinessException(500, "Failed to reset offset: " + e.getMessage());
- }
- }
-
- // ── Helper methods ──────────────────────────────────────────────────
-
- private Set<String> getAllMasterBrokerAddrs() throws Exception {
- Set<String> addrs = new HashSet<>();
- ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
- if (clusterInfo == null || clusterInfo.getBrokerAddrTable() == null) {
- return addrs;
- }
-
- for (BrokerData brokerData : clusterInfo.getBrokerAddrTable().values()) {
- if (brokerData.getBrokerAddrs() == null) {
- continue;
- }
- // Use master address (brokerId = 0) preferentially
- String masterAddr = brokerData.getBrokerAddrs().get(0L);
- if (masterAddr == null && !brokerData.getBrokerAddrs().isEmpty()) {
- masterAddr = brokerData.getBrokerAddrs().values().iterator().next();
- }
- if (masterAddr != null) {
- addrs.add(masterAddr);
- }
- }
- return addrs;
- }
-
- private String getClusterName() {
- try {
- ClusterInfo clusterInfo = adminExt.examineBrokerClusterInfo();
- if (clusterInfo != null && clusterInfo.getClusterAddrTable() != null
- && !clusterInfo.getClusterAddrTable().isEmpty()) {
- return clusterInfo.getClusterAddrTable().keySet().iterator().next();
- }
- } catch (Exception ignored) {
- }
- return "DefaultCluster";
- }
-
- private int toRocketMQPerm(TopicPerm perm) {
- if (perm == TopicPerm.RO) {
- return 4;
- }
- if (perm == TopicPerm.WO) {
- return 2;
- }
- return 6;
- }
-
- private TopicPerm fromRocketMQPerm(Integer perm) {
- if (perm != null && perm == 4) {
- return TopicPerm.RO;
- }
- if (perm != null && perm == 2) {
- return TopicPerm.WO;
- }
- return TopicPerm.RW;
- }
-}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQAdminConfig.java b/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQAdminConfig.java
deleted file mode 100644
index 8cf4e7f5..00000000
--- a/server/src/main/java/org/apache/rocketmq/studio/rocketmq/RocketMQAdminConfig.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.rocketmq.studio.rocketmq;
-
-import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-@EnableConfigurationProperties(RocketMQProperties.class)
-public class RocketMQAdminConfig {
-
- private static final Logger log = LoggerFactory.getLogger(RocketMQAdminConfig.class);
-
- @Bean(initMethod = "start", destroyMethod = "shutdown")
- @ConditionalOnProperty(prefix = "studio.rocketmq", name = "namesrv-addr")
- public DefaultMQAdminExt defaultMQAdminExt(
- @Value("${studio.rocketmq.namesrv-addr:}") String namesrvAddr) {
- log.info("Initializing DefaultMQAdminExt with namesrvAddr=[{}]", namesrvAddr);
- DefaultMQAdminExt adminExt = new DefaultMQAdminExt();
- adminExt.setNamesrvAddr(namesrvAddr);
- adminExt.setInstanceName("studio-admin-" + System.currentTimeMillis());
- return adminExt;
- }
-}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclDeleteRequestDTO.java b/server/src/main/java/org/apache/rocketmq/studio/settings/DataSourceDTO.java
similarity index 60%
rename from server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclDeleteRequestDTO.java
rename to server/src/main/java/org/apache/rocketmq/studio/settings/DataSourceDTO.java
index 2e051bb1..61626ad9 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclDeleteRequestDTO.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/settings/DataSourceDTO.java
@@ -14,19 +14,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.instance.acl;
+package org.apache.rocketmq.studio.settings;
import jakarta.validation.constraints.NotBlank;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
import lombok.Data;
-import lombok.NoArgsConstructor;
@Data
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-public class AclDeleteRequestDTO {
- @NotBlank(message = "id is required")
- private String id;
+public class DataSourceDTO {
+
+ private String key;
+
+ @NotBlank(message = "name is required")
+ private String name;
+
+ @NotBlank(message = "type is required")
+ private String type;
+
+ @NotBlank(message = "url is required")
+ private String url;
+
+ private String auth;
+
+ public DataSourceVO toDataSourceVO() {
+ return DataSourceVO.builder()
+ .key(key)
+ .name(name)
+ .type(type)
+ .url(url)
+ .auth(auth)
+ .build();
+ }
}
diff --git a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
index 40d79332..935a6da4 100644
--- a/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
+++ b/server/src/main/java/org/apache/rocketmq/studio/settings/SettingsController.java
@@ -17,7 +17,6 @@
package org.apache.rocketmq.studio.settings;
import org.apache.rocketmq.studio.common.domain.Result;
-import org.apache.rocketmq.studio.common.exception.BusinessException;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
@@ -53,13 +52,13 @@ public class SettingsController {
}
@PostMapping("/datasources/create")
- public Result<DataSourceVO> createDataSource(@Valid @RequestBody(required = false) DataSourceVO dataSource) {
- return Result.ok(settingsService.createDataSource(requireDataSource(dataSource)));
+ public Result<DataSourceVO> createDataSource(@Valid @RequestBody DataSourceDTO request) {
+ return Result.ok(settingsService.createDataSource(request.toDataSourceVO()));
}
@PostMapping("/datasources/update")
- public Result<DataSourceVO> updateDataSource(@Valid @RequestBody(required = false) DataSourceVO dataSource) {
- return Result.ok(settingsService.updateDataSource(requireDataSource(dataSource)));
+ public Result<DataSourceVO> updateDataSource(@Valid @RequestBody DataSourceDTO request) {
+ return Result.ok(settingsService.updateDataSource(request.toDataSourceVO()));
}
@PostMapping("/datasources/delete")
@@ -73,10 +72,4 @@ public class SettingsController {
return Result.ok(settingsService.testDataSource(request));
}
- private DataSourceVO requireDataSource(DataSourceVO dataSource) {
- if (dataSource == null) {
- throw new BusinessException(400, "Data source request is required");
- }
- return dataSource;
- }
}
diff --git a/server/src/main/resources/application-dev.yml b/server/src/main/resources/application-dev.yml
index 401febe3..f7efb59e 100644
--- a/server/src/main/resources/application-dev.yml
+++ b/server/src/main/resources/application-dev.yml
@@ -1,7 +1,7 @@
# Development profile
spring:
datasource:
- url: jdbc:h2:mem:rocketmq_studio;MODE=MySQL;DB_CLOSE_DELAY=-1;DATABASE_TO_LOWER=TRUE
+ url: jdbc:h2:mem:rocketmq;MODE=MySQL;DB_CLOSE_DELAY=-1;DATABASE_TO_LOWER=TRUE
username: sa
password:
driver-class-name: org.h2.Driver
diff --git a/server/src/main/resources/application.yml b/server/src/main/resources/application.yml
index ddd36def..9db5ce44 100644
--- a/server/src/main/resources/application.yml
+++ b/server/src/main/resources/application.yml
@@ -7,7 +7,7 @@ spring:
profiles:
active: dev
datasource:
- url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/rocketmq_studio?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC}
+ url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/rocketmq?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC}
username: ${SPRING_DATASOURCE_USERNAME:root}
password: ${SPRING_DATASOURCE_PASSWORD:studio123}
driver-class-name: com.mysql.cj.jdbc.Driver
diff --git a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterServiceTest.java b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterServiceTest.java
index 6100d4a9..1e6bcb9c 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterServiceTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/cluster/broker/ClusterServiceTest.java
@@ -33,7 +33,7 @@ import org.apache.rocketmq.studio.common.domain.enums.ClusterType;
import org.apache.rocketmq.studio.common.domain.enums.FlushDiskType;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.ops.audit.AuditService;
-import org.apache.rocketmq.studio.rocketmq.RocketMQBrokerConfigService;
+import org.apache.rocketmq.studio.provider.apache.RocketMQBrokerConfigService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
diff --git a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
index c10b9fae..8f3ff7e9 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceControllerTest.java
@@ -140,7 +140,7 @@ class InstanceControllerTest {
.content("null"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value(400))
- .andExpect(jsonPath("$.message").value("Instance request is required"));
+ .andExpect(jsonPath("$.message").value("Invalid request body"));
verifyNoInteractions(instanceService);
}
@@ -179,7 +179,7 @@ class InstanceControllerTest {
.content("null"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value(400))
- .andExpect(jsonPath("$.message").value("Instance request is required"));
+ .andExpect(jsonPath("$.message").value("Invalid request body"));
verifyNoInteractions(instanceService);
}
diff --git a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
index 096339c9..b998643e 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
@@ -17,13 +17,14 @@
package org.apache.rocketmq.studio.instance;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialRepository;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialVO;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialRepository;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialVO;
import org.apache.rocketmq.studio.common.domain.enums.InstanceType;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.provider.CloudCatalogProvider;
import org.apache.rocketmq.studio.provider.CloudInstanceDetailVO;
+import org.apache.rocketmq.studio.provider.InstanceProvider;
import org.apache.rocketmq.studio.provider.InstanceProviderRegistry;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -55,6 +56,9 @@ class InstanceServiceTest {
@Mock
private InstanceProviderRegistry providerRegistry;
+ @Mock
+ private InstanceProvider instanceProvider;
+
@InjectMocks
private InstanceService instanceService;
@@ -65,6 +69,7 @@ class InstanceServiceTest {
InstanceVO.builder().name("inst-2").build()
);
when(instanceRepository.findAll()).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(null, null);
@@ -78,6 +83,7 @@ class InstanceServiceTest {
InstanceVO.builder().name("proxy-1").type(InstanceType.PROXY).build()
);
when(instanceRepository.findByType(InstanceType.PROXY)).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(InstanceType.PROXY, null);
@@ -91,6 +97,7 @@ class InstanceServiceTest {
InstanceVO.builder().name("production").build()
);
when(instanceRepository.search("prod")).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(null, "prod");
@@ -104,6 +111,7 @@ class InstanceServiceTest {
InstanceVO.builder().name("production").build()
);
when(instanceRepository.search("prod")).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(null, " prod ");
@@ -117,6 +125,7 @@ class InstanceServiceTest {
InstanceVO.builder().name("production-proxy").type(InstanceType.PROXY).build()
);
when(instanceRepository.findByTypeAndSearch(InstanceType.PROXY, "prod")).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(InstanceType.PROXY, "prod");
@@ -130,6 +139,7 @@ class InstanceServiceTest {
InstanceVO.builder().name("production-proxy").type(InstanceType.PROXY).build()
);
when(instanceRepository.findByTypeAndSearch(InstanceType.PROXY, "prod")).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(InstanceType.PROXY, " prod ");
@@ -141,6 +151,7 @@ class InstanceServiceTest {
void listInstancesShouldIgnoreBlankSearch() {
List<InstanceVO> instances = List.of(InstanceVO.builder().name("inst").build());
when(instanceRepository.findAll()).thenReturn(instances);
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
List<InstanceVO> result = instanceService.listInstances(null, " ");
@@ -148,6 +159,44 @@ class InstanceServiceTest {
verify(instanceRepository).findAll();
}
+ @Test
+ void listInstancesShouldFillCountsThroughVendorProviderTest() {
+ InstanceVO apache = InstanceVO.builder().name("apache").build();
+ apache.setId("inst-apache");
+ InstanceVO aliyun = InstanceVO.builder().name("aliyun").vendor(InstanceVendor.ALIYUN).build();
+ aliyun.setId("inst-aliyun");
+ InstanceProvider aliyunProvider = org.mockito.Mockito.mock(InstanceProvider.class);
+ when(instanceRepository.findAll()).thenReturn(List.of(apache, aliyun));
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
+ when(providerRegistry.forVendor(InstanceVendor.ALIYUN)).thenReturn(aliyunProvider);
+ when(instanceProvider.countTopics("inst-apache")).thenReturn(3);
+ when(instanceProvider.countGroups("inst-apache")).thenReturn(2);
+ when(aliyunProvider.countTopics("inst-aliyun")).thenReturn(5);
+ when(aliyunProvider.countGroups("inst-aliyun")).thenReturn(4);
+
+ List<InstanceVO> result = instanceService.listInstances(null, null);
+
+ assertThat(result.get(0).getTopicCount()).isEqualTo(3);
+ assertThat(result.get(0).getConsumerGroupCount()).isEqualTo(2);
+ assertThat(result.get(1).getTopicCount()).isEqualTo(5);
+ assertThat(result.get(1).getConsumerGroupCount()).isEqualTo(4);
+ }
+
+ @Test
+ void listInstancesShouldKeepZeroCountsWhenProviderFailsTest() {
+ InstanceVO instance = InstanceVO.builder().name("broken").build();
+ instance.setId("inst-broken");
+ when(instanceRepository.findAll()).thenReturn(List.of(instance));
+ when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(instanceProvider);
+ when(instanceProvider.countTopics("inst-broken"))
+ .thenThrow(new IllegalStateException("admin unavailable"));
+
+ List<InstanceVO> result = instanceService.listInstances(null, null);
+
+ assertThat(result.get(0).getTopicCount()).isZero();
+ assertThat(result.get(0).getConsumerGroupCount()).isZero();
+ }
+
@Test
void createInstanceShouldThrowWhenRequestIsNull() {
assertThatThrownBy(() -> instanceService.createInstance(null))
diff --git a/server/src/test/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepositoryTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepositoryTest.java
index eba043f8..f796564b 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepositoryTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/instance/MybatisPlusInstanceRepositoryTest.java
@@ -31,13 +31,13 @@ import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@@ -56,15 +56,10 @@ class MybatisPlusInstanceRepositoryTest {
private MybatisPlusInstanceRepository repository;
@Test
- void findAllShouldPopulateCountsGroupedByInstance() {
+ void findAllShouldMapEntitiesWithoutCountsTest() {
when(instanceMapper.selectList(any(QueryWrapper.class)))
.thenReturn(List.of(entity("instance-direct-1", InstanceType.DIRECT),
entity("instance-proxy-1", InstanceType.PROXY)));
- when(topicMapper.selectMaps(any(QueryWrapper.class)))
- .thenReturn(List.of(Map.of("instance_id", "instance-proxy-1", "total", 3L)));
- when(groupMapper.selectMaps(any(QueryWrapper.class)))
- .thenReturn(List.of(Map.of("instance_id", "instance-proxy-1", "total", 2L),
- Map.of("instance_id", "instance-direct-1", "total", 1L)));
List<InstanceVO> result = repository.findAll();
@@ -74,9 +69,10 @@ class MybatisPlusInstanceRepositoryTest {
InstanceVO proxy = result.stream()
.filter(i -> "instance-proxy-1".equals(i.getId())).findFirst().orElseThrow();
assertThat(direct.getTopicCount()).isZero();
- assertThat(direct.getConsumerGroupCount()).isEqualTo(1);
- assertThat(proxy.getTopicCount()).isEqualTo(3);
- assertThat(proxy.getConsumerGroupCount()).isEqualTo(2);
+ assertThat(direct.getConsumerGroupCount()).isZero();
+ assertThat(proxy.getTopicCount()).isZero();
+ assertThat(proxy.getConsumerGroupCount()).isZero();
+ verifyNoInteractions(topicMapper, groupMapper);
}
@Test
@@ -92,8 +88,7 @@ class MybatisPlusInstanceRepositoryTest {
when(instanceMapper.selectList(any(QueryWrapper.class))).thenReturn(List.of());
assertThat(repository.findAll()).isEmpty();
- verify(topicMapper, never()).selectMaps(any(QueryWrapper.class));
- verify(groupMapper, never()).selectMaps(any(QueryWrapper.class));
+ verifyNoInteractions(topicMapper, groupMapper);
}
@Test
@@ -104,17 +99,31 @@ class MybatisPlusInstanceRepositoryTest {
}
@Test
- void findByIdShouldPopulateCountsForSingleInstance() {
+ void findByIdShouldNotComputeCountsTest() {
when(instanceMapper.selectById("instance-proxy-1")).thenReturn(entity("instance-proxy-1", InstanceType.PROXY));
- when(topicMapper.selectMaps(any(QueryWrapper.class)))
- .thenReturn(List.of(Map.of("instance_id", "instance-proxy-1", "total", 5L)));
- when(groupMapper.selectMaps(any(QueryWrapper.class))).thenReturn(List.of());
Optional<InstanceVO> result = repository.findById("instance-proxy-1");
assertThat(result).isPresent();
- assertThat(result.get().getTopicCount()).isEqualTo(5);
+ assertThat(result.get().getTopicCount()).isZero();
assertThat(result.get().getConsumerGroupCount()).isZero();
+ verifyNoInteractions(topicMapper, groupMapper);
+ }
+
+ @Test
+ void countTopicsByInstanceShouldDelegateToTopicMapperTest() {
+ when(topicMapper.selectCount(any(QueryWrapper.class))).thenReturn(5L);
+
+ assertThat(repository.countTopicsByInstance("instance-proxy-1")).isEqualTo(5L);
+ verify(topicMapper).selectCount(any(QueryWrapper.class));
+ }
+
+ @Test
+ void countGroupsByInstanceShouldDelegateToGroupMapperTest() {
+ when(groupMapper.selectCount(any(QueryWrapper.class))).thenReturn(2L);
+
+ assertThat(repository.countGroupsByInstance("instance-proxy-1")).isEqualTo(2L);
+ verify(groupMapper).selectCount(any(QueryWrapper.class));
}
@Test
diff --git a/server/src/test/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryServiceTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
similarity index 98%
rename from server/src/test/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryServiceTest.java
rename to server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
index 609d4aef..b9108bc4 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/queryhistory/QueryHistoryServiceTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/instance/message/QueryHistoryServiceTest.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.rocketmq.studio.queryhistory;
+package org.apache.rocketmq.studio.instance.message;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import org.apache.rocketmq.studio.auth.AuthenticatedUserContext;
diff --git a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/CloudMetadataProviderTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/CloudMetadataProviderTest.java
deleted file mode 100644
index 81b82889..00000000
--- a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/CloudMetadataProviderTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.rocketmq.studio.instance.topic;
-
-import org.apache.rocketmq.studio.common.exception.BusinessException;
-import org.assertj.core.api.ThrowableAssert;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-class CloudMetadataProviderTest {
-
- private final CloudMetadataProvider provider = new CloudMetadataProvider();
-
- @Test
- void consumerGroupQueriesShouldReturnProviderUnavailable() {
- assertUnavailable(() -> provider.listConsumerGroups("cluster-1", "order"));
- assertUnavailable(() -> provider.getGroupProgress("cg-order"));
- assertUnavailable(() -> provider.getGroupSubscriptions("cg-order"));
- }
-
- private void assertUnavailable(ThrowableAssert.ThrowingCallable callable) {
- assertThatThrownBy(callable)
- .isInstanceOf(BusinessException.class)
- .hasMessage("Consumer group metadata provider is not configured")
- .satisfies(ex -> assertThat(((BusinessException) ex).getCode()).isEqualTo(501));
- }
-}
diff --git a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
index 7ed2013b..caa06436 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/MetadataServiceTest.java
@@ -17,9 +17,14 @@
package org.apache.rocketmq.studio.instance.topic;
+import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.apache.rocketmq.studio.instance.group.ConsumerGroupVO;
+import org.apache.rocketmq.studio.provider.InstanceProvider;
import org.apache.rocketmq.studio.provider.InstanceProviderRegistry;
+import org.apache.rocketmq.studio.provider.apache.AdminClient;
+import org.apache.rocketmq.studio.provider.apache.MetadataProvider;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -31,6 +36,7 @@ import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@@ -47,9 +53,18 @@ class MetadataServiceTest {
@Mock
private InstanceProviderRegistry providerRegistry;
+ @Mock
+ private InstanceProvider apacheProvider;
+
@InjectMocks
private MetadataService metadataService;
+ @BeforeEach
+ void routeBlankInstanceIdsToApacheProvider() {
+ lenient().when(providerRegistry.forVendor(InstanceVendor.APACHE)).thenReturn(apacheProvider);
+ lenient().when(apacheProvider.vendor()).thenReturn(InstanceVendor.APACHE);
+ }
+
@Test
void listTopicsShouldReturnTopicsFromProvider() {
TopicVO topic = new TopicVO();
@@ -68,7 +83,7 @@ class MetadataServiceTest {
@Test
void listTopicsShouldReturnEmptyWhenNone() {
- when(metadataProvider.listTopics(null, null, "nonexistent")).thenReturn(List.of());
+ when(apacheProvider.listTopics(null, null, "nonexistent")).thenReturn(List.of());
List<TopicVO> result = metadataService.listTopics(null, null, "nonexistent");
@@ -89,12 +104,12 @@ class MetadataServiceTest {
@Test
void listTopicsShouldTreatBlankFiltersAsUnspecified() {
- when(metadataProvider.listTopics(null, null, null)).thenReturn(List.of());
+ when(apacheProvider.listTopics(null, null, null)).thenReturn(List.of());
List<TopicVO> result = metadataService.listTopics(" ", "\t", "");
assertThat(result).isEmpty();
- verify(metadataProvider).listTopics(null, null, null);
+ verify(apacheProvider).listTopics(null, null, null);
}
@Test
@@ -116,7 +131,7 @@ class MetadataServiceTest {
}
@Test
- void createTopicShouldDelegateToAdminClient() {
+ void createTopicShouldDelegateToApacheProvider() {
TopicVO input = new TopicVO();
input.setName("new-topic");
input.setWriteQueues(8);
@@ -127,19 +142,19 @@ class MetadataServiceTest {
created.setWriteQueues(8);
created.setReadQueues(8);
- when(adminClient.createTopic(any(TopicVO.class))).thenReturn(created);
+ when(apacheProvider.createTopic(any(), any(TopicVO.class))).thenReturn(created);
TopicVO result = metadataService.createTopic(input);
assertThat(result.getName()).isEqualTo("new-topic");
- verify(adminClient).createTopic(input);
+ verify(apacheProvider).createTopic(null, input);
}
@Test
- void deleteTopicShouldDelegateToAdminClient() {
+ void deleteTopicShouldDelegateToApacheProvider() {
metadataService.deleteTopic("topic-to-delete");
- verify(adminClient).deleteTopic("topic-to-delete");
+ verify(apacheProvider).deleteTopic(null, "topic-to-delete");
}
@Test
@@ -181,12 +196,12 @@ class MetadataServiceTest {
@Test
void listConsumerGroupsShouldPassSearchFilter() {
- when(metadataProvider.listConsumerGroups(null, "order")).thenReturn(List.of());
+ when(apacheProvider.listConsumerGroups(null, "order")).thenReturn(List.of());
List<ConsumerGroupVO> result = metadataService.listConsumerGroups(null, "order");
assertThat(result).isEmpty();
- verify(metadataProvider).listConsumerGroups(null, "order");
+ verify(apacheProvider).listConsumerGroups(null, "order");
}
@Test
@@ -201,11 +216,4 @@ class MetadataServiceTest {
verify(metadataProvider).listConsumerGroups("cluster-1", "order");
}
- @Test
- void listNamespacesShouldReportUnsupportedProviderCapability() {
- assertThatThrownBy(() -> metadataService.listNamespaces())
- .isInstanceOf(BusinessException.class)
- .hasMessage("Namespace discovery is not implemented by the current metadata provider")
- .satisfies(exception -> assertThat(((BusinessException) exception).getCode()).isEqualTo(501));
- }
}
diff --git a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/NamespaceControllerTest.java b/server/src/test/java/org/apache/rocketmq/studio/instance/topic/NamespaceControllerTest.java
deleted file mode 100644
index c052adca..00000000
--- a/server/src/test/java/org/apache/rocketmq/studio/instance/topic/NamespaceControllerTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.rocketmq.studio.instance.topic;
-
-import org.apache.rocketmq.studio.common.exception.BusinessException;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
-import org.springframework.boot.test.mock.mockito.MockBean;
-import org.springframework.test.web.servlet.MockMvc;
-
-import static org.mockito.Mockito.when;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-@WebMvcTest(NamespaceController.class)
-@AutoConfigureMockMvc(addFilters = false)
-class NamespaceControllerTest {
-
- @Autowired
- private MockMvc mockMvc;
-
- @MockBean
- private MetadataService metadataService;
-
- @Test
- void listNamespacesShouldReturnStructuredUnsupportedCapabilityError() throws Exception {
- when(metadataService.listNamespaces()).thenThrow(
- new BusinessException(501, "Namespace discovery is not implemented by the current metadata provider"));
-
- mockMvc.perform(get("/api/namespaces"))
- .andExpect(status().isNotImplemented())
- .andExpect(jsonPath("$.code").value(501))
- .andExpect(jsonPath("$.message")
- .value("Namespace discovery is not implemented by the current metadata provider"));
- }
-}
diff --git a/server/src/test/java/org/apache/rocketmq/studio/model/UserTest.java b/server/src/test/java/org/apache/rocketmq/studio/model/UserTest.java
index 37a0d522..b992d10f 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/model/UserTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/model/UserTest.java
@@ -28,8 +28,8 @@ class UserTest {
String value = user.toString();
- assertThat(value).contains("name='admin'");
- assertThat(value).contains("password='******'");
+ assertThat(value).contains("name=admin");
+ assertThat(value).doesNotContain("password");
assertThat(value).doesNotContain("plain-secret");
}
}
diff --git a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmControllerTest.java b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmControllerTest.java
index 0b6a0a3e..d84ccd44 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmControllerTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmControllerTest.java
@@ -63,12 +63,13 @@ class LlmControllerTest {
mockMvc.perform(get("/api/llm/config"))
.andExpect(status().isOk())
- .andExpect(jsonPath("$.provider").value("openai"))
- .andExpect(jsonPath("$.apiKey").doesNotExist())
- .andExpect(jsonPath("$.apiKeyConfigured").value(true))
- .andExpect(jsonPath("$.apiBase").value("https://api.openai.com/v1"))
- .andExpect(jsonPath("$.model").value("gpt-4o"))
- .andExpect(jsonPath("$.enabled").value(true));
+ .andExpect(jsonPath("$.code").value(200))
+ .andExpect(jsonPath("$.data.provider").value("openai"))
+ .andExpect(jsonPath("$.data.apiKey").doesNotExist())
+ .andExpect(jsonPath("$.data.apiKeyConfigured").value(true))
+ .andExpect(jsonPath("$.data.apiBase").value("https://api.openai.com/v1"))
+ .andExpect(jsonPath("$.data.model").value("gpt-4o"))
+ .andExpect(jsonPath("$.data.enabled").value(true));
}
@Test
@@ -84,8 +85,8 @@ class LlmControllerTest {
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(config)))
.andExpect(status().isOk())
- .andExpect(jsonPath("$.status").value(0))
- .andExpect(jsonPath("$.msg").value("saved"));
+ .andExpect(jsonPath("$.data.status").value(0))
+ .andExpect(jsonPath("$.data.msg").value("saved"));
verify(llmConfigService).saveConfig(any(LlmConfigVO.class));
}
@@ -102,8 +103,8 @@ class LlmControllerTest {
.model("llama3")
.build())))
.andExpect(status().isOk())
- .andExpect(jsonPath("$.status").value(0))
- .andExpect(jsonPath("$.msg").value("Configuration accepted"));
+ .andExpect(jsonPath("$.data.status").value(0))
+ .andExpect(jsonPath("$.data.msg").value("Configuration accepted"));
}
@Test
@@ -114,8 +115,8 @@ class LlmControllerTest {
mockMvc.perform(get("/api/llm/models"))
.andExpect(status().isOk())
- .andExpect(jsonPath("$.status").value(0))
- .andExpect(jsonPath("$.data[0].id").value("gpt-4o"))
- .andExpect(jsonPath("$.data[1].name").value("GPT-4"));
+ .andExpect(jsonPath("$.data.status").value(0))
+ .andExpect(jsonPath("$.data.data[0].id").value("gpt-4o"))
+ .andExpect(jsonPath("$.data.data[1].name").value("GPT-4"));
}
}
diff --git a/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactoryTest.java b/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactoryTest.java
index 766072a4..05aa00a3 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactoryTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunClientFactoryTest.java
@@ -21,8 +21,8 @@ import com.aliyun.sdk.service.rocketmq20220801.AsyncClient;
import com.aliyun.sdk.service.rocketmq20220801.models.ListRegionsRequest;
import com.aliyun.sdk.service.rocketmq20220801.models.ListRegionsResponse;
import com.aliyun.sdk.service.rocketmq20220801.models.ListRegionsResponseBody;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialRepository;
-import org.apache.rocketmq.studio.cloud.credential.CloudCredentialVO;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialRepository;
+import org.apache.rocketmq.studio.provider.credential.CloudCredentialVO;
import org.apache.rocketmq.studio.common.domain.enums.InstanceVendor;
import org.apache.rocketmq.studio.common.exception.BusinessException;
import org.junit.jupiter.api.BeforeEach;
diff --git a/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java b/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
index 330f1bcd..645d9537 100644
--- a/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
+++ b/server/src/test/java/org/apache/rocketmq/studio/provider/alibaba/AliyunInstanceProviderTest.java
@@ -426,6 +426,45 @@ class AliyunInstanceProviderTest {
.build();
}
+ @Test
+ void countTopicsShouldReuseListTopicsSizeTest() {
+ stubInstance();
+ stubCallThrough();
+ when(asyncClient.listTopics(any(ListTopicsRequest.class)))
+ .thenReturn(CompletableFuture.completedFuture(topicsResponse(
+ topicRow("topic-a", "NORMAL"),
+ topicRow("topic-b", "FIFO"))));
+
+ assertThat(provider.countTopics(STUDIO_INSTANCE_ID)).isEqualTo(2);
+ }
+
+ @Test
+ void countGroupsShouldReuseListConsumerGroupsSizeTest() {
+ stubInstance();
+ stubCallThrough();
+ ListConsumerGroupsResponse response = ListConsumerGroupsResponse.create().toBuilder()
+ .statusCode(200)
+ .body(ListConsumerGroupsResponseBody.builder()
+ .data(ListConsumerGroupsResponseBody.Data.builder()
+ .list(List.of(
+ ListConsumerGroupsResponseBody.List.builder()
+ .consumerGroupId("GID_one")
+ .build(),
+ ListConsumerGroupsResponseBody.List.builder()
+ .consumerGroupId("GID_two")
+ .build()))
+ .pageNumber(1L)
+ .pageSize(100L)
+ .totalCount(2L)
+ .build())
+ .build())
+ .build();
+ when(asyncClient.listConsumerGroups(any()))
+ .thenReturn(CompletableFuture.completedFuture(response));
+
+ assertThat(provider.countGroups(STUDIO_INSTANCE_ID)).isEqualTo(2);
+ }
+
@Test
void normalizeDeliveryOrderTypeShouldMapFifoToOrderlyTest() {
org.junit.jupiter.api.Assertions.assertEquals("Orderly",
diff --git a/server/src/test/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProviderTest.java b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProviderTest.java
new file mode 100644
index 00000000..62db28a8
--- /dev/null
+++ b/server/src/test/java/org/apache/rocketmq/studio/provider/apache/ApacheInstanceProviderTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
... 697 lines suppressed ...