Skip to content

Commit 823bce2

Browse files
authored
feat: add topic message type
add message type
1 parent 2fb0fce commit 823bce2

File tree

8 files changed

+168
-49
lines changed

8 files changed

+168
-49
lines changed

src/main/java/org/apache/rocketmq/dashboard/model/request/TopicConfigInfo.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class TopicConfigInfo {
3131
private int perm;
3232
private boolean order;
3333

34+
private String messageType;
3435
public List<String> getClusterNameList() {
3536
return clusterNameList;
3637
}
@@ -91,6 +92,18 @@ public void setOrder(boolean order) {
9192
this.order = order;
9293
}
9394

95+
96+
public String getMessageType() {
97+
return messageType;
98+
}
99+
100+
public void setMessageType(String messageType) {
101+
this.messageType = messageType;
102+
}
103+
104+
105+
106+
94107
@Override
95108
public boolean equals(Object o) {
96109
if (this == o)
@@ -102,12 +115,13 @@ public boolean equals(Object o) {
102115
readQueueNums == that.readQueueNums &&
103116
perm == that.perm &&
104117
order == that.order &&
105-
Objects.equal(topicName, that.topicName);
118+
Objects.equal(topicName, that.topicName) &&
119+
Objects.equal(messageType, that.messageType);
106120
}
107121

108122
@Override
109123
public int hashCode() {
110-
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order);
124+
return Objects.hashCode(topicName, writeQueueNums, readQueueNums, perm, order,messageType);
111125
}
112126

113127
}

src/main/java/org/apache/rocketmq/dashboard/service/impl/ClusterServiceImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.rocketmq.dashboard.service.impl;
1919

20+
import org.apache.rocketmq.common.attribute.TopicMessageType;
2021
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
2122
import org.apache.rocketmq.remoting.protocol.body.KVTable;
2223
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
@@ -30,8 +31,10 @@
3031
import org.springframework.stereotype.Service;
3132

3233
import javax.annotation.Resource;
34+
import java.util.Arrays;
3335
import java.util.Map;
3436
import java.util.Properties;
37+
import java.util.stream.Collectors;
3538

3639
@Service
3740
public class ClusterServiceImpl implements ClusterService {
@@ -56,6 +59,9 @@ public Map<String, Object> list() {
5659
}
5760
resultMap.put("clusterInfo", clusterInfo);
5861
resultMap.put("brokerServer", brokerServer);
62+
// add messageType
63+
resultMap.put("messageTypes", Arrays.stream(TopicMessageType.values()).sorted()
64+
.collect(Collectors.toMap(TopicMessageType::getValue, messageType ->String.format("MESSAGE_TYPE_%s",messageType.getValue()))));
5965
return resultMap;
6066
}
6167
catch (Exception err) {

src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java

Lines changed: 111 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,37 @@
1818
package org.apache.rocketmq.dashboard.service.impl;
1919

2020
import com.google.common.base.Throwables;
21+
import com.google.common.collect.ImmutableMap;
2122
import com.google.common.collect.Lists;
2223
import com.google.common.collect.Sets;
23-
import java.util.stream.Collectors;
2424
import org.apache.commons.lang3.StringUtils;
2525
import org.apache.rocketmq.acl.common.AclClientRPCHook;
2626
import org.apache.rocketmq.acl.common.SessionCredentials;
2727
import org.apache.rocketmq.client.producer.DefaultMQProducer;
2828
import org.apache.rocketmq.client.producer.SendResult;
29+
import org.apache.rocketmq.client.producer.TransactionListener;
30+
import org.apache.rocketmq.client.producer.TransactionMQProducer;
31+
import org.apache.rocketmq.client.producer.LocalTransactionState;
2932
import org.apache.rocketmq.client.trace.TraceContext;
3033
import org.apache.rocketmq.client.trace.TraceDispatcher;
3134
import org.apache.rocketmq.common.MixAll;
3235
import org.apache.rocketmq.common.TopicConfig;
33-
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
36+
import org.apache.rocketmq.common.attribute.TopicMessageType;
3437
import org.apache.rocketmq.common.message.Message;
35-
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
36-
import org.apache.rocketmq.remoting.protocol.body.GroupList;
37-
import org.apache.rocketmq.remoting.protocol.body.TopicList;
38-
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
39-
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
38+
import org.apache.rocketmq.common.message.MessageExt;
4039
import org.apache.rocketmq.common.topic.TopicValidator;
4140
import org.apache.rocketmq.dashboard.config.RMQConfigure;
4241
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
4342
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
4443
import org.apache.rocketmq.dashboard.service.AbstractCommonService;
4544
import org.apache.rocketmq.dashboard.service.TopicService;
4645
import org.apache.rocketmq.remoting.RPCHook;
46+
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
47+
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
48+
import org.apache.rocketmq.remoting.protocol.body.GroupList;
49+
import org.apache.rocketmq.remoting.protocol.body.TopicList;
50+
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
51+
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
4752
import org.apache.rocketmq.tools.command.CommandUtil;
4853
import org.joor.Reflect;
4954
import org.springframework.beans.BeanUtils;
@@ -55,6 +60,11 @@
5560
import java.util.List;
5661
import java.util.Set;
5762
import java.util.concurrent.ArrayBlockingQueue;
63+
import java.util.concurrent.ConcurrentHashMap;
64+
import java.util.concurrent.atomic.AtomicInteger;
65+
import java.util.stream.Collectors;
66+
67+
import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTRIBUTE;
5868

5969
@Service
6070
public class TopicServiceImpl extends AbstractCommonService implements TopicService {
@@ -68,18 +78,18 @@ public TopicList fetchAllTopicList(boolean skipSysProcess, boolean skipRetryAndD
6878
TopicList allTopics = mqAdminExt.fetchAllTopicList();
6979
TopicList sysTopics = getSystemTopicList();
7080
Set<String> topics =
71-
allTopics.getTopicList().stream().map(topic -> {
72-
if (!skipSysProcess && sysTopics.getTopicList().contains(topic)) {
73-
topic = String.format("%s%s", "%SYS%", topic);
74-
}
75-
return topic;
76-
}).filter(topic -> {
77-
if (skipRetryAndDlq) {
78-
return !(topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
79-
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX));
80-
}
81-
return true;
82-
}).collect(Collectors.toSet());
81+
allTopics.getTopicList().stream().map(topic -> {
82+
if (!skipSysProcess && sysTopics.getTopicList().contains(topic)) {
83+
topic = String.format("%s%s", "%SYS%", topic);
84+
}
85+
return topic;
86+
}).filter(topic -> {
87+
if (skipRetryAndDlq) {
88+
return !(topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)
89+
|| topic.startsWith(MixAll.DLQ_GROUP_TOPIC_PREFIX));
90+
}
91+
return true;
92+
}).collect(Collectors.toSet());
8393
allTopics.getTopicList().clear();
8494
allTopics.getTopicList().addAll(topics);
8595
return allTopics;
@@ -123,10 +133,15 @@ public GroupList queryTopicConsumerInfo(String topic) {
123133
public void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest) {
124134
TopicConfig topicConfig = new TopicConfig();
125135
BeanUtils.copyProperties(topicCreateOrUpdateRequest, topicConfig);
136+
String messageType = topicCreateOrUpdateRequest.getMessageType();
137+
if (StringUtils.isBlank(messageType)) {
138+
messageType = TopicMessageType.NORMAL.name();
139+
}
140+
topicConfig.setAttributes(ImmutableMap.of("+".concat(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName()), messageType));
126141
try {
127142
ClusterInfo clusterInfo = mqAdminExt.examineBrokerClusterInfo();
128143
for (String brokerName : changeToBrokerNameSet(clusterInfo.getClusterAddrTable(),
129-
topicCreateOrUpdateRequest.getClusterNameList(), topicCreateOrUpdateRequest.getBrokerNameList())) {
144+
topicCreateOrUpdateRequest.getClusterNameList(), topicCreateOrUpdateRequest.getBrokerNameList())) {
130145
mqAdminExt.createAndUpdateTopicConfig(clusterInfo.getBrokerAddrTable().get(brokerName).selectBrokerAddr(), topicConfig);
131146
}
132147
} catch (Exception err) {
@@ -156,6 +171,11 @@ public List<TopicConfigInfo> examineTopicConfig(String topic) {
156171
TopicConfig topicConfig = examineTopicConfig(topic, brokerData.getBrokerName());
157172
BeanUtils.copyProperties(topicConfig, topicConfigInfo);
158173
topicConfigInfo.setBrokerNameList(Lists.newArrayList(brokerData.getBrokerName()));
174+
String messageType = topicConfig.getAttributes().get(TOPIC_MESSAGE_TYPE_ATTRIBUTE.getName());
175+
if (StringUtils.isBlank(messageType)) {
176+
messageType = TopicMessageType.UNSPECIFIED.name();
177+
}
178+
topicConfigInfo.setMessageType(messageType);
159179
topicConfigInfoList.add(topicConfigInfo);
160180
}
161181
return topicConfigInfoList;
@@ -226,6 +246,12 @@ public DefaultMQProducer buildDefaultMQProducer(String producerGroup, RPCHook rp
226246
return defaultMQProducer;
227247
}
228248

249+
public TransactionMQProducer buildTransactionMQProducer(String producerGroup, RPCHook rpcHook, boolean traceEnabled) {
250+
TransactionMQProducer defaultMQProducer = new TransactionMQProducer(null, producerGroup, rpcHook, traceEnabled, TopicValidator.RMQ_SYS_TRACE_TOPIC);
251+
defaultMQProducer.setUseTLS(configure.isUseTLS());
252+
return defaultMQProducer;
253+
}
254+
229255
private TopicList getSystemTopicList() {
230256
RPCHook rpcHook = null;
231257
boolean isEnableAcl = !StringUtils.isEmpty(configure.getAccessKey()) && !StringUtils.isEmpty(configure.getSecretKey());
@@ -249,32 +275,61 @@ private TopicList getSystemTopicList() {
249275

250276
@Override
251277
public SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest) {
252-
DefaultMQProducer producer = null;
278+
List<TopicConfigInfo> topicConfigInfos = examineTopicConfig(sendTopicMessageRequest.getTopic());
279+
String messageType = topicConfigInfos.get(0).getMessageType();
253280
AclClientRPCHook rpcHook = null;
254281
if (configure.isACLEnabled()) {
255282
rpcHook = new AclClientRPCHook(new SessionCredentials(
256-
configure.getAccessKey(),
257-
configure.getSecretKey()
283+
configure.getAccessKey(),
284+
configure.getSecretKey()
258285
));
259286
}
260-
producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
261-
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
262-
producer.setNamesrvAddr(configure.getNamesrvAddr());
263-
try {
264-
producer.start();
265-
Message msg = new Message(sendTopicMessageRequest.getTopic(),
266-
sendTopicMessageRequest.getTag(),
267-
sendTopicMessageRequest.getKey(),
268-
sendTopicMessageRequest.getMessageBody().getBytes()
269-
);
270-
return producer.send(msg);
271-
} catch (Exception e) {
272-
Throwables.throwIfUnchecked(e);
273-
throw new RuntimeException(e);
274-
} finally {
275-
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
276-
producer.shutdown();
287+
if (TopicMessageType.TRANSACTION.getValue().equals(messageType)) {
288+
// transaction message
289+
TransactionListener transactionListener = new TransactionListenerImpl();
290+
291+
TransactionMQProducer producer = buildTransactionMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
292+
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
293+
producer.setNamesrvAddr(configure.getNamesrvAddr());
294+
producer.setTransactionListener(transactionListener);
295+
try {
296+
producer.start();
297+
Message msg = new Message(sendTopicMessageRequest.getTopic(),
298+
sendTopicMessageRequest.getTag(),
299+
sendTopicMessageRequest.getKey(),
300+
sendTopicMessageRequest.getMessageBody().getBytes()
301+
);
302+
return producer.sendMessageInTransaction(msg, null);
303+
} catch (Exception e) {
304+
Throwables.throwIfUnchecked(e);
305+
throw new RuntimeException(e);
306+
} finally {
307+
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
308+
producer.shutdown();
309+
}
310+
} else {
311+
// no transaction message
312+
DefaultMQProducer producer = null;
313+
producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook, sendTopicMessageRequest.isTraceEnabled());
314+
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
315+
producer.setNamesrvAddr(configure.getNamesrvAddr());
316+
try {
317+
producer.start();
318+
Message msg = new Message(sendTopicMessageRequest.getTopic(),
319+
sendTopicMessageRequest.getTag(),
320+
sendTopicMessageRequest.getKey(),
321+
sendTopicMessageRequest.getMessageBody().getBytes()
322+
);
323+
return producer.send(msg);
324+
} catch (Exception e) {
325+
Throwables.throwIfUnchecked(e);
326+
throw new RuntimeException(e);
327+
} finally {
328+
waitSendTraceFinish(producer, sendTopicMessageRequest.isTraceEnabled());
329+
producer.shutdown();
330+
}
277331
}
332+
278333
}
279334

280335
private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnabled) {
@@ -296,4 +351,20 @@ private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnable
296351
} catch (Exception ignore) {
297352
}
298353
}
354+
355+
static class TransactionListenerImpl implements TransactionListener {
356+
private AtomicInteger transactionIndex = new AtomicInteger(0);
357+
358+
private ConcurrentHashMap<String, Integer> localTrans = new ConcurrentHashMap<>();
359+
360+
@Override
361+
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
362+
return LocalTransactionState.COMMIT_MESSAGE;
363+
}
364+
365+
@Override
366+
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
367+
return LocalTransactionState.COMMIT_MESSAGE;
368+
}
369+
}
299370
}

src/main/resources/application.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ rocketmq:
4242
# configure multiple namesrv addresses to manage multiple different clusters
4343
namesrvAddrs:
4444
- 127.0.0.1:9876
45-
- 127.0.0.2:9876
45+
# - 127.0.0.2:9876
46+
# - 10.151.47.32:9876;10.151.47.33:9876;10.151.47.34:9876
47+
# - 10.151.47.30:9876
4648
# if you use rocketmq version < 3.5.8, rocketmq.config.isVIPChannel should be false.default true
4749
isVIPChannel:
4850
# timeout for mqadminExt, default 5000ms
@@ -58,8 +60,8 @@ rocketmq:
5860
loginRequired: false
5961
useTLS: false
6062
# set the accessKey and secretKey if you used acl
61-
accessKey: # if version > 4.4.0
62-
secretKey: # if version > 4.4.0
63+
# accessKey: rocketmq2
64+
# secretKey: 12345678
6365

6466
threadpool:
6567
config:

src/main/resources/static/src/i18n/en.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,5 +123,11 @@ var en = {
123123
"GROUP_PERM":"Group Permission",
124124
"SYNCHRONIZE":"Synchronize Data",
125125
"SHOW":"Show",
126-
"HIDE":"Hide"
126+
"HIDE":"Hide",
127+
"MESSAGE_TYPE":"messageType",
128+
"MESSAGE_TYPE_UNSPECIFIED": "UNSPECIFIED, is NORMAL",
129+
"MESSAGE_TYPE_NORMAL": "NORMAL",
130+
"MESSAGE_TYPE_FIFO": "FIFO",
131+
"MESSAGE_TYPE_DELAY": "DELAY",
132+
"MESSAGE_TYPE_TRANSACTION": "TRANSACTION",
127133
}

src/main/resources/static/src/i18n/zh.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,11 @@ var zh = {
124124
"GROUP_PERM":"消费组权限",
125125
"SYNCHRONIZE":"同步",
126126
"SHOW":"显示",
127-
"HIDE":"隐藏"
127+
"HIDE":"隐藏",
128+
"MESSAGE_TYPE":"消息类型",
129+
"MESSAGE_TYPE_UNSPECIFIED": "未指定,为普通消息",
130+
"MESSAGE_TYPE_NORMAL": "普通消息",
131+
"MESSAGE_TYPE_FIFO": "顺序消息",
132+
"MESSAGE_TYPE_DELAY": "定时/延时消息",
133+
"MESSAGE_TYPE_TRANSACTION": "事务消息",
128134
}

src/main/resources/static/src/topic.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
328328
var bIsUpdate = true;
329329
if (request == null) {
330330
request = [{
331-
writeQueueNums: 16,
332-
readQueueNums: 16,
331+
writeQueueNums: 8,
332+
readQueueNums: 8,
333333
perm: 6,
334334
order: false,
335335
topicName: "",
@@ -355,6 +355,7 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
355355
topicRequestList: request,
356356
allClusterNameList: Object.keys(resp.data.clusterInfo.clusterAddrTable),
357357
allBrokerNameList: Object.keys(resp.data.brokerServer),
358+
allMessageTypeList: resp.data.messageTypes,
358359
bIsUpdate: bIsUpdate,
359360
writeOperationEnabled: $scope.writeOperationEnabled
360361
}

src/main/resources/static/view/pages/topic.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
<button class="btn btn-raised btn-sm btn-primary" type="button"
6464
ng-click="openUpdateDialog(topic, sysFlag)">topic {{'CONFIG' |translate}}
6565
</button>
66+
<!-- todo 发送消息,根据消息类型判断-->
6667
<button class="btn btn-raised btn-sm btn-primary" type="button"
6768
ng-show="{{!sysFlag}}"
6869
ng-click="openSendTopicMessageDialog(topic)">{{'SEND_MSG' | translate}}
@@ -189,6 +190,18 @@ <h4 class="modal-title">{{'TOPIC_CHANGE'| translate }}</h4>
189190
<span class="text-danger" ng-show="addAppForm.topicName.$error.required">{{'TOPIC_NAME'|translate}}不能为空.</span>
190191
</div>
191192
</div>
193+
<!-- 设置topic 类型 -->
194+
<div class="form-group">
195+
<label class="control-label col-sm-2">{{'MESSAGE_TYPE'|translate}}:</label>
196+
<div class="col-sm-10">
197+
<select name="mySelectMessageType" chosen ng-disabled="ngDialogData.bIsUpdate"
198+
ng-model="item.messageType"
199+
ng-options="messageType as value | translate disable when messageType=='UNSPECIFIED' for (messageType , value) in ngDialogData.allMessageTypeList"
200+
>
201+
<option value=""></option>
202+
</select>
203+
</div>
204+
</div>
192205
<div class="form-group">
193206
<label class="control-label col-sm-2">{{'WRITE_QUEUE_NUMS'|translate}}:</label>
194207
<div class="col-sm-10">

0 commit comments

Comments
 (0)