fixed compatible and code format

This commit is contained in:
jianghang.loujh
2022-05-13 11:59:57 +08:00
parent 25be0259a4
commit 33733aef25
5 changed files with 167 additions and 163 deletions

View File

@@ -1,7 +1,5 @@
package com.alibaba.otter.canal.connector.pulsarmq.config; package com.alibaba.otter.canal.connector.pulsarmq.config;
import org.joda.time.Seconds;
/** /**
* PulsarMQ配置 * PulsarMQ配置
* *
@@ -10,6 +8,7 @@ import org.joda.time.Seconds;
* @since 1 by chad at 2021/9/15 新增配置文件 * @since 1 by chad at 2021/9/15 新增配置文件
*/ */
public class PulsarMQConstants { public class PulsarMQConstants {
public static final String ROOT = "pulsarmq"; public static final String ROOT = "pulsarmq";
/** /**
* pulsar服务连接地址 * pulsar服务连接地址
@@ -62,5 +61,4 @@ public class PulsarMQConstants {
*/ */
public static final String PULSARMQ_ADMIN_SERVER_URL = ROOT + "." + "adminServerUrl"; public static final String PULSARMQ_ADMIN_SERVER_URL = ROOT + "." + "adminServerUrl";
} }

View File

@@ -4,11 +4,13 @@ import com.alibaba.otter.canal.connector.core.config.MQProperties;
/** /**
* Pulsar生产者配置 * Pulsar生产者配置
*
* @author chad * @author chad
* @date 2021/9/15 11:23 * @date 2021/9/15 11:23
* @since 1 by chad at 2021/9/15 新增 * @since 1 by chad at 2021/9/15 新增
*/ */
public class PulsarMQProducerConfig extends MQProperties { public class PulsarMQProducerConfig extends MQProperties {
/** /**
* pulsar服务连接地址 * pulsar服务连接地址
* <p> * <p>

View File

@@ -1,20 +1,24 @@
package com.alibaba.otter.canal.connector.pulsarmq.consumer; package com.alibaba.otter.canal.connector.pulsarmq.consumer;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.apache.pulsar.client.api.*;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.otter.canal.common.utils.MQUtil; import com.alibaba.otter.canal.common.utils.MQUtil;
import com.alibaba.otter.canal.connector.core.config.CanalConstants; import com.alibaba.otter.canal.connector.core.config.CanalConstants;
import com.alibaba.otter.canal.connector.core.consumer.CommonMessage; import com.alibaba.otter.canal.connector.core.consumer.CommonMessage;
import com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer; import com.alibaba.otter.canal.connector.core.spi.CanalMsgConsumer;
import com.alibaba.otter.canal.connector.core.spi.SPI; import com.alibaba.otter.canal.connector.core.spi.SPI;
import com.alibaba.otter.canal.connector.core.util.CanalMessageSerializerUtil;
import com.alibaba.otter.canal.connector.core.util.MessageUtil;
import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants; import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants;
import com.alibaba.otter.canal.protocol.Message;
import com.alibaba.otter.canal.protocol.exception.CanalClientException; import com.alibaba.otter.canal.protocol.exception.CanalClientException;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.apache.pulsar.client.api.*;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
/** /**
* Pulsar consumer SPI 实现 * Pulsar consumer SPI 实现
@@ -24,6 +28,7 @@ import java.util.concurrent.TimeUnit;
*/ */
@SPI("pulsarmq") @SPI("pulsarmq")
public class CanalPulsarMQConsumer implements CanalMsgConsumer { public class CanalPulsarMQConsumer implements CanalMsgConsumer {
/** /**
* 连接pulsar客户端 * 连接pulsar客户端
*/ */
@@ -58,8 +63,7 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
*/ */
private int batchSize = 30; private int batchSize = 30;
/** /**
* 与{@code batchSize}一起决定批量获取的数据大小 * 与{@code batchSize}一起决定批量获取的数据大小 当:
* 当:
* <p> * <p>
* 1. {@code batchSize} 条消息未消费时<br/> * 1. {@code batchSize} 条消息未消费时<br/>
* 2. 距上一次批量消费时间达到{@code batchTimeoutSeconds}秒时 * 2. 距上一次批量消费时间达到{@code batchTimeoutSeconds}秒时
@@ -106,9 +110,12 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
} }
this.serviceUrl = properties.getProperty(PulsarMQConstants.PULSARMQ_SERVER_URL); this.serviceUrl = properties.getProperty(PulsarMQConstants.PULSARMQ_SERVER_URL);
this.roleToken = properties.getProperty(PulsarMQConstants.PULSARMQ_ROLE_TOKEN); this.roleToken = properties.getProperty(PulsarMQConstants.PULSARMQ_ROLE_TOKEN);
//this.subscriptName = properties.getProperty(PulsarMQConstants.PULSARMQ_SUBSCRIPT_NAME); this.subscriptName = properties.getProperty(PulsarMQConstants.PULSARMQ_SUBSCRIPT_NAME);
// 采用groupId作为subscriptName,避免所有的都是同一个订阅者名称 // 采用groupId作为subscriptName,避免所有的都是同一个订阅者名称
if (StringUtils.isEmpty(this.subscriptName)) {
this.subscriptName = groupId; this.subscriptName = groupId;
}
if (StringUtils.isEmpty(this.subscriptName)) { if (StringUtils.isEmpty(this.subscriptName)) {
throw new RuntimeException("Pulsar Consumer subscriptName required"); throw new RuntimeException("Pulsar Consumer subscriptName required");
} }
@@ -153,9 +160,9 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
} }
// 连接创建客户端 // 连接创建客户端
try { try {
//AuthenticationDataProvider // AuthenticationDataProvider
ClientBuilder builder = PulsarClient.builder().serviceUrl(serviceUrl); ClientBuilder builder = PulsarClient.builder().serviceUrl(serviceUrl);
if(StringUtils.isNotEmpty(roleToken)) { if (StringUtils.isNotEmpty(roleToken)) {
builder.authentication(AuthenticationFactory.token(roleToken)); builder.authentication(AuthenticationFactory.token(roleToken));
} }
pulsarClient = builder.build(); pulsarClient = builder.build();
@@ -177,8 +184,7 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
// 调用consumer.negativeAcknowledge(message) (即nack)来表示消费失败的消息 // 调用consumer.negativeAcknowledge(message) (即nack)来表示消费失败的消息
// 在指定的时间进行重新消费,默认是1分钟。 // 在指定的时间进行重新消费,默认是1分钟。
.negativeAckRedeliveryDelay(this.redeliveryDelaySeconds, TimeUnit.SECONDS) .negativeAckRedeliveryDelay(this.redeliveryDelaySeconds, TimeUnit.SECONDS)
.subscriptionName(this.subscriptName) .subscriptionName(this.subscriptName);
;
if (this.isRetry) { if (this.isRetry) {
DeadLetterPolicy.DeadLetterPolicyBuilder dlqBuilder = DeadLetterPolicy.builder() DeadLetterPolicy.DeadLetterPolicyBuilder dlqBuilder = DeadLetterPolicy.builder()
// 最大重试次数 // 最大重试次数
@@ -191,17 +197,15 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
dlqBuilder.deadLetterTopic(dlqTopic); dlqBuilder.deadLetterTopic(dlqTopic);
} }
//默认关闭,如果需要重试则开启 // 默认关闭,如果需要重试则开启
builder.enableRetry(true) builder.enableRetry(true).deadLetterPolicy(dlqBuilder.build());
.deadLetterPolicy(dlqBuilder.build());
} }
// ack超时 // ack超时
builder.ackTimeout(this.ackTimeoutSeconds, TimeUnit.SECONDS); builder.ackTimeout(this.ackTimeoutSeconds, TimeUnit.SECONDS);
// pulsar批量获取消息设置 // pulsar批量获取消息设置
builder.batchReceivePolicy(new BatchReceivePolicy.Builder() builder.batchReceivePolicy(new BatchReceivePolicy.Builder().maxNumMessages(this.batchSize)
.maxNumMessages(this.batchSize)
.timeout(this.getBatchTimeoutSeconds, TimeUnit.SECONDS) .timeout(this.getBatchTimeoutSeconds, TimeUnit.SECONDS)
.build()); .build());
@@ -225,17 +229,14 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
this.lastGetBatchMessage = messages; this.lastGetBatchMessage = messages;
for (org.apache.pulsar.client.api.Message<byte[]> msg : messages) { for (org.apache.pulsar.client.api.Message<byte[]> msg : messages) {
byte[] data = msg.getData(); byte[] data = msg.getData();
/*if (!this.flatMessage) { if (!this.flatMessage) {
Message message = CanalMessageSerializerUtil.deserializer(data); Message message = CanalMessageSerializerUtil.deserializer(data);
List<CommonMessage> list = MessageUtil.convert(message); List<CommonMessage> list = MessageUtil.convert(message);
messageList.addAll(list); messageList.addAll(list);
} else { } else {
CommonMessage commonMessage = JSON.parseObject(data, CommonMessage.class); CommonMessage commonMessage = JSON.parseObject(data, CommonMessage.class);
messageList.add(commonMessage); messageList.add(commonMessage);
}*/ }
// CanalMessageSerializerUtil.deserializer(data) 会转换失败
CommonMessage commonMessage = JSON.parseObject(data, CommonMessage.class);
messageList.add(commonMessage);
} }
} catch (PulsarClientException e) { } catch (PulsarClientException e) {
throw new CanalClientException("Receive pulsar batch message error", e); throw new CanalClientException("Receive pulsar batch message error", e);

View File

@@ -1,5 +1,17 @@
package com.alibaba.otter.canal.connector.pulsarmq.producer; package com.alibaba.otter.canal.connector.pulsarmq.producer;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang.StringUtils;
import org.apache.pulsar.client.admin.PulsarAdmin;
import org.apache.pulsar.client.admin.PulsarAdminException;
import org.apache.pulsar.client.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter.Feature; import com.alibaba.fastjson2.JSONWriter.Feature;
import com.alibaba.otter.canal.common.utils.ExecutorTemplate; import com.alibaba.otter.canal.common.utils.ExecutorTemplate;
@@ -16,19 +28,6 @@ import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants;
import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQProducerConfig; import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQProducerConfig;
import com.alibaba.otter.canal.protocol.CanalEntry; import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.FlatMessage; import com.alibaba.otter.canal.protocol.FlatMessage;
import org.apache.commons.lang.StringUtils;
import org.apache.pulsar.client.admin.PulsarAdmin;
import org.apache.pulsar.client.admin.PulsarAdminException;
import org.apache.pulsar.client.api.*;
import org.apache.pulsar.shade.com.google.gson.JsonParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* PulsarMQ Producer SPI 实现 * PulsarMQ Producer SPI 实现
@@ -39,15 +38,14 @@ import java.util.stream.Collectors;
@SPI("pulsarmq") @SPI("pulsarmq")
public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQProducer { public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQProducer {
private static final Logger logger = LoggerFactory.getLogger(CanalPulsarMQProducer.class);
private static final Map<String, Producer<byte[]>> PRODUCERS = new HashMap<>();
protected ThreadPoolExecutor sendPartitionExecutor;
/** /**
* 消息体分区属性名称 * 消息体分区属性名称
*/ */
public static final String MSG_PROPERTY_PARTITION_NAME = "partitionNum"; public static final String MSG_PROPERTY_PARTITION_NAME = "partitionNum";
private static final Logger logger = LoggerFactory
.getLogger(CanalPulsarMQProducer.class);
private static final Map<String, Producer<byte[]>> PRODUCERS = new HashMap<>();
protected ThreadPoolExecutor sendPartitionExecutor;
/** /**
* pulsar客户端,管理连接 * pulsar客户端,管理连接
*/ */
@@ -70,7 +68,7 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
ClientBuilder builder = PulsarClient.builder() ClientBuilder builder = PulsarClient.builder()
// 填写pulsar的连接地址 // 填写pulsar的连接地址
.serviceUrl(pulsarMQProducerConfig.getServerUrl()); .serviceUrl(pulsarMQProducerConfig.getServerUrl());
if(StringUtils.isNotEmpty(pulsarMQProducerConfig.getRoleToken())) { if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getRoleToken())) {
// 角色权限认证的token // 角色权限认证的token
builder.authentication(AuthenticationFactory.token(pulsarMQProducerConfig.getRoleToken())); builder.authentication(AuthenticationFactory.token(pulsarMQProducerConfig.getRoleToken()));
} }
@@ -80,7 +78,7 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
} }
// 初始化Pulsar admin // 初始化Pulsar admin
if(StringUtils.isNotEmpty(pulsarMQProducerConfig.getAdminServerUrl())) { if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getAdminServerUrl())) {
try { try {
pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsarMQProducerConfig.getAdminServerUrl()).build(); pulsarAdmin = PulsarAdmin.builder().serviceHttpUrl(pulsarMQProducerConfig.getAdminServerUrl()).build();
} catch (PulsarClientException e) { } catch (PulsarClientException e) {
@@ -119,12 +117,13 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
if (!StringUtils.isEmpty(roleToken)) { if (!StringUtils.isEmpty(roleToken)) {
tmpProperties.setRoleToken(roleToken); tmpProperties.setRoleToken(roleToken);
} }
String topicTenantPrefix = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_TOPIC_TENANT_PREFIX); String topicTenantPrefix = PropertiesUtils.getProperty(properties,
PulsarMQConstants.PULSARMQ_TOPIC_TENANT_PREFIX);
if (!StringUtils.isEmpty(topicTenantPrefix)) { if (!StringUtils.isEmpty(topicTenantPrefix)) {
tmpProperties.setTopicTenantPrefix(topicTenantPrefix); tmpProperties.setTopicTenantPrefix(topicTenantPrefix);
} }
String adminServerUrl = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_ADMIN_SERVER_URL); String adminServerUrl = PropertiesUtils.getProperty(properties, PulsarMQConstants.PULSARMQ_ADMIN_SERVER_URL);
if(!StringUtils.isEmpty(adminServerUrl)) { if (!StringUtils.isEmpty(adminServerUrl)) {
tmpProperties.setAdminServerUrl(adminServerUrl); tmpProperties.setAdminServerUrl(adminServerUrl);
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@@ -154,9 +153,8 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
try { try {
if (!StringUtils.isEmpty(destination.getDynamicTopic())) { if (!StringUtils.isEmpty(destination.getDynamicTopic())) {
// 动态topic // 动态topic
Map<String, com.alibaba.otter.canal.protocol.Message> messageMap = MQMessageUtils.messageTopics(message, Map<String, com.alibaba.otter.canal.protocol.Message> messageMap = MQMessageUtils
destination.getTopic(), .messageTopics(message, destination.getTopic(), destination.getDynamicTopic());
destination.getDynamicTopic());
for (Map.Entry<String, com.alibaba.otter.canal.protocol.Message> entry : messageMap.entrySet()) { for (Map.Entry<String, com.alibaba.otter.canal.protocol.Message> entry : messageMap.entrySet()) {
String topicName = entry.getKey().replace('.', '_'); String topicName = entry.getKey().replace('.', '_');
@@ -195,7 +193,8 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
* @author chad * @author chad
* @since 1.0.0 by chad at 2021/9/2: 新增 * @since 1.0.0 by chad at 2021/9/2: 新增
*/ */
public void send(final MQDestination destination, String topicName, com.alibaba.otter.canal.protocol.Message message) { public void send(final MQDestination destination, String topicName,
com.alibaba.otter.canal.protocol.Message message) {
// 获取当前topic的分区数 // 获取当前topic的分区数
Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName, Integer partitionNum = MQMessageUtils.parseDynamicTopicPartition(topicName,
@@ -204,7 +203,7 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
partitionNum = destination.getPartitionsNum(); partitionNum = destination.getPartitionsNum();
} }
// 创建多分区topic // 创建多分区topic
if(pulsarAdmin!=null && partitionNum!=null && partitionNum>0 && PRODUCERS.get(topicName)==null) { if (pulsarAdmin != null && partitionNum != null && partitionNum > 0 && PRODUCERS.get(topicName) == null) {
createMultipleTopic(topicName, partitionNum); createMultipleTopic(topicName, partitionNum);
} }
@@ -304,7 +303,8 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
try { try {
MessageId msgResultId = producer.newMessage() MessageId msgResultId = producer.newMessage()
.property(MSG_PROPERTY_PARTITION_NAME, String.valueOf(partitionNum)) .property(MSG_PROPERTY_PARTITION_NAME, String.valueOf(partitionNum))
.value(msgBytes).send(); .value(msgBytes)
.send();
// todo 判断发送结果 // todo 判断发送结果
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Send Message to topic:{} Result: {}", topic, msgResultId); logger.debug("Send Message to topic:{} Result: {}", topic, msgResultId);
@@ -328,8 +328,7 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
Producer<byte[]> producer = getProducer(topic); Producer<byte[]> producer = getProducer(topic);
for (FlatMessage f : flatMessages) { for (FlatMessage f : flatMessages) {
try { try {
MessageId msgResultId = producer MessageId msgResultId = producer.newMessage()
.newMessage()
.property(MSG_PROPERTY_PARTITION_NAME, String.valueOf(partition)) .property(MSG_PROPERTY_PARTITION_NAME, String.valueOf(partition))
.value(JSON.toJSONBytes(f, Feature.WriteNulls)) .value(JSON.toJSONBytes(f, Feature.WriteNulls))
.send() .send()
@@ -346,10 +345,11 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
/** /**
* 创建多分区topic * 创建多分区topic
*
* @param topic * @param topic
* @param partitionNum * @param partitionNum
*/ */
private void createMultipleTopic(String topic,Integer partitionNum) { private void createMultipleTopic(String topic, Integer partitionNum) {
// 拼接topic前缀 // 拼接topic前缀
PulsarMQProducerConfig pulsarMQProperties = (PulsarMQProducerConfig) this.mqProperties; PulsarMQProducerConfig pulsarMQProperties = (PulsarMQProducerConfig) this.mqProperties;
String prefix = pulsarMQProperties.getTopicTenantPrefix(); String prefix = pulsarMQProperties.getTopicTenantPrefix();
@@ -368,8 +368,10 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
// TODO 无论是否报错,都继续后续的操作,此处不进行阻塞 // TODO 无论是否报错,都继续后续的操作,此处不进行阻塞
} }
} }
/** /**
* 获取topic * 获取topic
*
* @param topic * @param topic
* @return * @return
*/ */
@@ -412,6 +414,26 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
return producer; return producer;
} }
@Override
public void stop() {
logger.info("## Stop PulsarMQ producer##");
for (Producer p : PRODUCERS.values()) {
try {
if (null != p && p.isConnected()) {
p.close();
}
} catch (PulsarClientException e) {
logger.warn("close producer name: {}, topic: {}, error: {}",
p.getProducerName(),
p.getTopic(),
e.getMessage());
}
}
super.stop();
}
/** /**
* Pulsar自定义路由策略 * Pulsar自定义路由策略
* *
@@ -421,9 +443,10 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
* @since 2 by chad at 2021/9/17 修改为msg自带目标分区 * @since 2 by chad at 2021/9/17 修改为msg自带目标分区
*/ */
private static class MessageRouterImpl implements MessageRouter { private static class MessageRouterImpl implements MessageRouter {
private String topicLocal; private String topicLocal;
public MessageRouterImpl(String topicLocal) { public MessageRouterImpl(String topicLocal){
this.topicLocal = topicLocal; this.topicLocal = topicLocal;
} }
@@ -435,7 +458,8 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
try { try {
partition = Integer.parseInt(partitionStr); partition = Integer.parseInt(partitionStr);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
logger.warn("Parse msg {} property failed for value: {}", MSG_PROPERTY_PARTITION_NAME, partitionStr); logger
.warn("Parse msg {} property failed for value: {}", MSG_PROPERTY_PARTITION_NAME, partitionStr);
} }
} }
// topic创建时设置的分区数 // topic创建时设置的分区数
@@ -447,21 +471,4 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
return partition; return partition;
} }
} }
@Override
public void stop() {
logger.info("## Stop PulsarMQ producer##");
for (Producer p : PRODUCERS.values()) {
try {
if (null != p && p.isConnected()) {
p.close();
}
} catch (PulsarClientException e) {
logger.warn("close producer name: {}, topic: {}, error: {}", p.getProducerName(), p.getTopic(), e.getMessage());
}
}
super.stop();
}
} }

View File

@@ -1,23 +1,19 @@
package com.alibaba.otter.canal.connector.pulsarmq.consumer; package com.alibaba.otter.canal.connector.pulsarmq.consumer;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.otter.canal.connector.core.config.CanalConstants; import com.alibaba.otter.canal.connector.core.config.CanalConstants;
import com.alibaba.otter.canal.connector.core.consumer.CommonMessage; import com.alibaba.otter.canal.connector.core.consumer.CommonMessage;
import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants; import com.alibaba.otter.canal.connector.pulsarmq.config.PulsarMQConstants;
import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;
/** /**
* @author chad * @author chad