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

mikexue pushed a commit to branch eventmesh-connector
in repository https://gitbox.apache.org/repos/asf/eventmesh.git


The following commit(s) were added to refs/heads/eventmesh-connector by this 
push:
     new e81a1f425 [ISSUE #3913] Add Source Connector RocketMQ Module (#3914)
e81a1f425 is described below

commit e81a1f4251e4c2a931f2416b2e306ed4cdcdef5f
Author: mike_xwm <[email protected]>
AuthorDate: Fri May 12 17:30:49 2023 +0800

    [ISSUE #3913] Add Source Connector RocketMQ Module (#3914)
---
 .../source-connector-rocketmq/build.gradle         |  41 ++++++++
 .../source-connector-rocketmq/gradle.properties    |  17 ++++
 .../connector/rocketmq/EventMeshTestUtils.java     | 113 +++++++++++++++++++++
 .../connector/rocketmq/RocketMQSourceWorker.java   |  60 +++++++++++
 .../source/connector/rocketmq/UtilsConstants.java  |  52 ++++++++++
 .../rocketmq/config/RocketMQSourceConfig.java      |  63 ++++++++++++
 .../connector/RocketMQSourceConnector.java         | 107 +++++++++++++++++++
 settings.gradle                                    |   1 +
 8 files changed, 454 insertions(+)

diff --git a/eventmesh-connectors/source-connector-rocketmq/build.gradle 
b/eventmesh-connectors/source-connector-rocketmq/build.gradle
new file mode 100644
index 000000000..180094cf2
--- /dev/null
+++ b/eventmesh-connectors/source-connector-rocketmq/build.gradle
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+List rocketmq = [
+        "org.apache.rocketmq:rocketmq-client:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-broker:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-common:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-store:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-namesrv:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-tools:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-remoting:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-logging:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-test:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-filter:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-acl:$rocketmq_version",
+        "org.apache.rocketmq:rocketmq-srvutil:$rocketmq_version",
+
+]
+
+dependencies {
+    implementation project(":eventmesh-connectors:eventmesh-connector-api")
+    implementation project(":eventmesh-sdk-java")
+    implementation rocketmq
+    compileOnly 'org.projectlombok:lombok'
+    annotationProcessor 'org.projectlombok:lombok'
+}
diff --git a/eventmesh-connectors/source-connector-rocketmq/gradle.properties 
b/eventmesh-connectors/source-connector-rocketmq/gradle.properties
new file mode 100644
index 000000000..89a6e4612
--- /dev/null
+++ b/eventmesh-connectors/source-connector-rocketmq/gradle.properties
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+rocketmq_version=4.9.5
\ No newline at end of file
diff --git 
a/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/EventMeshTestUtils.java
 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/EventMeshTestUtils.java
new file mode 100644
index 000000000..8e96ef01c
--- /dev/null
+++ 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/EventMeshTestUtils.java
@@ -0,0 +1,113 @@
+/*
+ * 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.eventmesh.source.connector.rocketmq;
+
+import static 
org.apache.eventmesh.common.protocol.tcp.Command.RESPONSE_TO_SERVER;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.ThreadLocalRandom;
+import org.apache.eventmesh.client.tcp.common.EventMeshCommon;
+import org.apache.eventmesh.client.tcp.common.MessageUtils;
+import org.apache.eventmesh.common.protocol.tcp.EventMeshMessage;
+import org.apache.eventmesh.common.protocol.tcp.Header;
+import org.apache.eventmesh.common.protocol.tcp.Package;
+import org.apache.eventmesh.common.protocol.tcp.UserAgent;
+import org.apache.eventmesh.common.utils.JsonUtils;
+
+public class EventMeshTestUtils {
+
+    private static final int SEQ_LENGTH = 10;
+
+    private static final String ASYNC_MSG_BODY = "testAsyncMessage";
+
+    private static final String DEFAULT_TTL_MS = "30000";
+
+    // generate pub-client
+    public static UserAgent generateClient1() {
+        final UserAgent agent = UserAgent.builder()
+            .env(UtilsConstants.ENV)
+            .host(UtilsConstants.HOST)
+            .password(generateRandomString(UtilsConstants.PASSWORD_LENGTH))
+            .username(UtilsConstants.USER_NAME)
+            .group(UtilsConstants.GROUP)
+            .path(UtilsConstants.PATH)
+            .port(UtilsConstants.PORT_1)
+            .subsystem(UtilsConstants.SUB_SYSTEM_1)
+            .pid(UtilsConstants.PID_1)
+            .version(UtilsConstants.VERSION)
+            .idc(UtilsConstants.IDC)
+            .build();
+        return MessageUtils.generatePubClient(agent);
+    }
+
+    // generate sub-client
+    public static UserAgent generateClient2() {
+        final UserAgent agent = UserAgent.builder()
+            .env(UtilsConstants.ENV)
+            .host(UtilsConstants.HOST)
+            .password(generateRandomString(UtilsConstants.PASSWORD_LENGTH))
+            .username(UtilsConstants.USER_NAME)
+            .group(UtilsConstants.GROUP)
+            .path(UtilsConstants.PATH)
+            .port(UtilsConstants.PORT_2)
+            .subsystem(UtilsConstants.SUB_SYSTEM_2)
+            .pid(UtilsConstants.PID_2)
+            .version(UtilsConstants.VERSION)
+            .idc(UtilsConstants.IDC)
+            .build();
+        return MessageUtils.generateSubClient(agent);
+    }
+
+    public static Package rrResponse(final EventMeshMessage request) {
+        final Package msg = new Package();
+        msg.setHeader(new Header(RESPONSE_TO_SERVER, 0, null, 
generateRandomString(SEQ_LENGTH)));
+        msg.setBody(request);
+        return msg;
+    }
+
+    private static String generateRandomString(final int length) {
+        final StringBuilder builder = new StringBuilder(length);
+        for (int i = 0; i < length; i++) {
+            builder.append((char) ThreadLocalRandom.current().nextInt(48, 57));
+        }
+        return builder.toString();
+    }
+
+    public static CloudEvent generateCloudEventV1(String destination, String 
message) {
+        final Map<String, String> content = new HashMap<>();
+        content.put(UtilsConstants.CONTENT, message);
+
+        return CloudEventBuilder.v1()
+            .withId(UUID.randomUUID().toString())
+            .withSubject(destination)
+            .withSource(URI.create("/"))
+            .withDataContentType("application/cloudevents+json")
+            .withType(EventMeshCommon.CLOUD_EVENTS_PROTOCOL_NAME)
+            
.withData(Objects.requireNonNull(JsonUtils.toJSONString(content)).getBytes(StandardCharsets.UTF_8))
+            .withExtension(UtilsConstants.TTL, DEFAULT_TTL_MS)
+            .build();
+    }
+
+}
diff --git 
a/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/RocketMQSourceWorker.java
 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/RocketMQSourceWorker.java
new file mode 100644
index 000000000..142c68e95
--- /dev/null
+++ 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/RocketMQSourceWorker.java
@@ -0,0 +1,60 @@
+package org.apache.eventmesh.source.connector.rocketmq;
+
+import io.cloudevents.CloudEvent;
+import java.util.List;
+import org.apache.eventmesh.client.tcp.EventMeshTCPClient;
+import org.apache.eventmesh.client.tcp.EventMeshTCPClientFactory;
+import org.apache.eventmesh.client.tcp.conf.EventMeshTCPClientConfig;
+import org.apache.eventmesh.common.protocol.tcp.UserAgent;
+import org.apache.eventmesh.connector.api.data.ConnectRecord;
+import 
org.apache.eventmesh.source.connector.rocketmq.config.RocketMQSourceConfig;
+import 
org.apache.eventmesh.source.connector.rocketmq.connector.RocketMQSourceConnector;
+
+public class RocketMQSourceWorker {
+
+    public static final String SOURCE_CONSUMER_GROUP = 
"DEFAULT-CONSUMER-GROUP";
+    public static final String SOURCE_CONNECT_NAMESRVADDR = "127.0.0.1:9877";
+    public static final String SOURCE_TOPIC = "TopicTest";
+
+    public static final String DESTINATION = "SourceTopic";
+
+
+    public static void main(String[] args) throws Exception {
+
+        UserAgent userAgent = EventMeshTestUtils.generateClient1();
+        EventMeshTCPClientConfig eventMeshTcpClientConfig = 
EventMeshTCPClientConfig.builder()
+            .host("127.0.0.1")
+            .port(10002)
+            .userAgent(userAgent)
+            .build();
+
+        final EventMeshTCPClient<CloudEvent> client =
+            
EventMeshTCPClientFactory.createEventMeshTCPClient(eventMeshTcpClientConfig, 
CloudEvent.class);
+
+        client.init();
+
+        RocketMQSourceConnector rocketMQSourceConnector = new 
RocketMQSourceConnector();
+
+        RocketMQSourceConfig rocketMQSourceConfig = new RocketMQSourceConfig();
+
+        rocketMQSourceConfig.setSourceNameserver(SOURCE_CONNECT_NAMESRVADDR);
+        rocketMQSourceConfig.setSourceTopic(SOURCE_TOPIC);
+        rocketMQSourceConfig.setSourceGroup(SOURCE_CONSUMER_GROUP);
+
+        rocketMQSourceConnector.init(rocketMQSourceConfig);
+
+        rocketMQSourceConnector.start();
+
+        while(true) {
+            List<ConnectRecord> connectorRecordList = 
rocketMQSourceConnector.poll();
+            for(ConnectRecord connectRecord : connectorRecordList) {
+                // todo:connectorRecord 转换 cloudEvents
+                CloudEvent event = 
EventMeshTestUtils.generateCloudEventV1(connectRecord.getExtension("topic"), 
connectRecord.getData().toString());
+                client.publish(event, 3000);
+                Thread.sleep(500);
+            }
+        }
+
+    }
+
+}
diff --git 
a/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/UtilsConstants.java
 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/UtilsConstants.java
new file mode 100644
index 000000000..29cfa028e
--- /dev/null
+++ 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/UtilsConstants.java
@@ -0,0 +1,52 @@
+/*
+ * 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.eventmesh.source.connector.rocketmq;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class UtilsConstants {
+
+    public static final String ENV = "test";
+    public static final String HOST = "localhost";
+    public static final Integer PASSWORD_LENGTH = 8;
+    public static final String USER_NAME = "PU4283";
+    public static final String GROUP = "EventmeshTestGroup";
+    public static final String PATH = "/data/app/umg_proxy";
+    public static final Integer PORT_1 = 8362;
+    public static final Integer PORT_2 = 9362;
+    public static final String SUB_SYSTEM_1 = "5023";
+    public static final String SUB_SYSTEM_2 = "5017";
+    public static final Integer PID_1 = 32_893;
+    public static final Integer PID_2 = 42_893;
+    public static final String VERSION = "2.0.11";
+    public static final String IDC = "FT";
+    /**
+     * PROPERTY KEY NAME .
+     */
+    public static final String MSG_TYPE = "msgtype";
+    public static final String TTL = "ttl";
+    public static final String KEYS = "keys";
+    public static final String REPLY_TO = "replyto";
+    public static final String PROPERTY_MESSAGE_REPLY_TO = 
"propertymessagereplyto";
+    public static final String CONTENT = "content";
+
+
+}
diff --git 
a/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/config/RocketMQSourceConfig.java
 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/config/RocketMQSourceConfig.java
new file mode 100644
index 000000000..4b5f54829
--- /dev/null
+++ 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/config/RocketMQSourceConfig.java
@@ -0,0 +1,63 @@
+/*
+ * 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.eventmesh.source.connector.rocketmq.config;
+
+import org.apache.eventmesh.connector.api.config.SourceConfig;
+
+public class RocketMQSourceConfig extends SourceConfig {
+
+    String connectorName;
+
+    String sourceNameserver;
+
+    String sourceTopic;
+
+    String sourceGroup;
+
+    public String getConnectorName() {
+        return connectorName;
+    }
+
+    public void setConnectorName(String connectorName) {
+        this.connectorName = connectorName;
+    }
+
+    public String getSourceNameserver() {
+        return sourceNameserver;
+    }
+
+    public void setSourceNameserver(String sourceNameserver) {
+        this.sourceNameserver = sourceNameserver;
+    }
+
+    public String getSourceTopic() {
+        return sourceTopic;
+    }
+
+    public void setSourceTopic(String sourceTopic) {
+        this.sourceTopic = sourceTopic;
+    }
+
+    public String getSourceGroup() {
+        return sourceGroup;
+    }
+
+    public void setSourceGroup(String sourceGroup) {
+        this.sourceGroup = sourceGroup;
+    }
+}
diff --git 
a/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/connector/RocketMQSourceConnector.java
 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/connector/RocketMQSourceConnector.java
new file mode 100644
index 000000000..751e6ef75
--- /dev/null
+++ 
b/eventmesh-connectors/source-connector-rocketmq/src/main/java/org/apache/eventmesh/source/connector/rocketmq/connector/RocketMQSourceConnector.java
@@ -0,0 +1,107 @@
+/*
+ * 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.eventmesh.source.connector.rocketmq.connector;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.eventmesh.connector.api.config.Config;
+import org.apache.eventmesh.connector.api.data.ConnectRecord;
+import org.apache.eventmesh.connector.api.data.RecordOffset;
+import org.apache.eventmesh.connector.api.data.RecordPartition;
+import org.apache.eventmesh.connector.api.source.Source;
+import 
org.apache.eventmesh.source.connector.rocketmq.config.RocketMQSourceConfig;
+import org.apache.rocketmq.client.consumer.DefaultLitePullConsumer;
+import org.apache.rocketmq.common.message.MessageExt;
+
+public class RocketMQSourceConnector implements Source {
+
+    private RocketMQSourceConfig sourceConfig;
+
+    private final DefaultLitePullConsumer consumer = new 
DefaultLitePullConsumer();
+
+    @Override
+    public Class<? extends Config> configClass() {
+        return RocketMQSourceConfig.class;
+    }
+
+    @Override
+    public void init(Config config) throws Exception {
+        // init config for rocketmq source connector
+        this.sourceConfig = (RocketMQSourceConfig) config;
+        consumer.setConsumerGroup(sourceConfig.getSourceGroup());
+        consumer.setNamesrvAddr(sourceConfig.getSourceNameserver());
+    }
+
+    @Override
+    public void start() throws Exception {
+        consumer.subscribe(sourceConfig.getSourceTopic(), "*");
+        consumer.start();
+    }
+
+    @Override
+    public void commit(ConnectRecord record) {
+
+    }
+
+    @Override
+    public String name() {
+        return this.sourceConfig.getConnectorName();
+    }
+
+    @Override
+    public void stop() {
+        consumer.unsubscribe(sourceConfig.getSourceTopic());
+        consumer.shutdown();
+    }
+
+    @Override
+    public List<ConnectRecord> poll() {
+        List<MessageExt> messageExts = consumer.poll();
+        List<ConnectRecord> connectRecords = new 
ArrayList<>(messageExts.size());
+        System.out.printf("%s Receive New Messages: %s %n", 
Thread.currentThread().getName(), messageExts);
+        for (MessageExt messageExt : messageExts) {
+            Long timestamp = System.currentTimeMillis();
+            byte[] body = messageExt.getBody();
+            String bodyStr = new String(body, StandardCharsets.UTF_8);
+            RecordPartition recordPartition = 
convertToRecordPartition(messageExt.getTopic(),
+                messageExt.getBrokerName(), messageExt.getQueueId());
+            RecordOffset recordOffset = 
convertToRecordOffset(messageExt.getQueueOffset());
+            ConnectRecord connectRecord = new ConnectRecord(recordPartition, 
recordOffset, timestamp, bodyStr);
+            connectRecord.addExtension("topic", messageExt.getTopic());
+            connectRecords.add(connectRecord);
+        }
+        return connectRecords;
+    }
+
+    public static RecordOffset convertToRecordOffset(Long offset) {
+        Map<String, String> offsetMap = new HashMap<>();
+        offsetMap.put("queueOffset", offset + "");
+        return new RecordOffset(offsetMap);
+    }
+
+    public static RecordPartition convertToRecordPartition(String topic, 
String brokerName, int queueId) {
+        Map<String, String> map = new HashMap<>();
+        map.put("topic", topic);
+        map.put("brokerName", brokerName);
+        map.put("queueId", queueId + "");
+        return new RecordPartition(map);
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index d6dfaa6a1..722fa0ab7 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -24,6 +24,7 @@ include 'eventmesh-starter'
 include 'eventmesh-examples'
 include 'eventmesh-spi'
 include 'eventmesh-connectors:eventmesh-connector-api'
+include 'eventmesh-connectors:source-connector-rocketmq'
 include 'eventmesh-storage-plugin:eventmesh-storage-api'
 include 'eventmesh-storage-plugin:eventmesh-storage-standalone'
 include 'eventmesh-storage-plugin:eventmesh-storage-kafka'


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to