mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
reformat
This commit is contained in:
@@ -65,8 +65,9 @@ public class ES8xTemplate implements ESTemplate {
|
|||||||
if (mapping.getId() != null) {
|
if (mapping.getId() != null) {
|
||||||
String parentVal = (String) esFieldData.remove("$parent_routing");
|
String parentVal = (String) esFieldData.remove("$parent_routing");
|
||||||
if (mapping.isUpsert()) {
|
if (mapping.isUpsert()) {
|
||||||
ESUpdateRequest updateRequest = esConnection.new ES8xUpdateRequest(mapping.getIndex(),
|
ESUpdateRequest updateRequest = esConnection.new ES8xUpdateRequest(mapping.getIndex(), pkVal.toString())
|
||||||
pkVal.toString()).setDoc(esFieldData).setDocAsUpsert(true);
|
.setDoc(esFieldData)
|
||||||
|
.setDocAsUpsert(true);
|
||||||
if (StringUtils.isNotEmpty(parentVal)) {
|
if (StringUtils.isNotEmpty(parentVal)) {
|
||||||
updateRequest.setRouting(parentVal);
|
updateRequest.setRouting(parentVal);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,21 @@
|
|||||||
package com.alibaba.otter.canal.client.adapter.es8x.support;
|
package com.alibaba.otter.canal.client.adapter.es8x.support;
|
||||||
|
|
||||||
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.HttpHost;
|
import org.apache.http.HttpHost;
|
||||||
import org.apache.http.auth.AuthScope;
|
import org.apache.http.auth.AuthScope;
|
||||||
@@ -32,20 +47,7 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.net.ssl.SSLContext;
|
import com.alibaba.otter.canal.client.adapter.es.core.support.ESBulkRequest;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ES 连接器, 只支持 Rest 方式
|
* ES 连接器, 只支持 Rest 方式
|
||||||
@@ -59,7 +61,7 @@ public class ESConnection {
|
|||||||
|
|
||||||
private RestHighLevelClient restHighLevelClient;
|
private RestHighLevelClient restHighLevelClient;
|
||||||
|
|
||||||
public ESConnection(String[] hosts, Map<String, String> properties) throws UnknownHostException {
|
public ESConnection(String[] hosts, Map<String, String> properties) throws UnknownHostException{
|
||||||
String caPath = properties.get("security.ca.path");
|
String caPath = properties.get("security.ca.path");
|
||||||
if (StringUtils.isNotEmpty(caPath)) {
|
if (StringUtils.isNotEmpty(caPath)) {
|
||||||
connectEsWithCa(hosts, properties, caPath);
|
connectEsWithCa(hosts, properties, caPath);
|
||||||
@@ -67,6 +69,7 @@ public class ESConnection {
|
|||||||
connectEsWithoutCa(hosts, properties);
|
connectEsWithoutCa(hosts, properties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void connectEsWithCa(String[] hosts, Map<String, String> properties, String caPath) {
|
private void connectEsWithCa(String[] hosts, Map<String, String> properties, String caPath) {
|
||||||
Path caCertificatePath = Paths.get(caPath);
|
Path caCertificatePath = Paths.get(caPath);
|
||||||
try (InputStream is = Files.newInputStream(caCertificatePath)) {
|
try (InputStream is = Files.newInputStream(caCertificatePath)) {
|
||||||
@@ -75,8 +78,7 @@ public class ESConnection {
|
|||||||
KeyStore trustStore = KeyStore.getInstance("pkcs12");
|
KeyStore trustStore = KeyStore.getInstance("pkcs12");
|
||||||
trustStore.load(null, null);
|
trustStore.load(null, null);
|
||||||
trustStore.setCertificateEntry("ca", trustedCa);
|
trustStore.setCertificateEntry("ca", trustedCa);
|
||||||
SSLContextBuilder sslContextBuilder = SSLContexts.custom()
|
SSLContextBuilder sslContextBuilder = SSLContexts.custom().loadTrustMaterial(trustStore, null);
|
||||||
.loadTrustMaterial(trustStore, null);
|
|
||||||
final SSLContext sslContext = sslContextBuilder.build();
|
final SSLContext sslContext = sslContextBuilder.build();
|
||||||
|
|
||||||
HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);
|
HttpHost[] httpHosts = Arrays.stream(hosts).map(this::createHttpHost).toArray(HttpHost[]::new);
|
||||||
@@ -86,13 +88,15 @@ public class ESConnection {
|
|||||||
String[] nameAndPwdArr = nameAndPwd.split(":");
|
String[] nameAndPwdArr = nameAndPwd.split(":");
|
||||||
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
||||||
credentialsProvider.setCredentials(AuthScope.ANY,
|
credentialsProvider.setCredentials(AuthScope.ANY,
|
||||||
new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));
|
new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));
|
||||||
restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> {
|
restClientBuilder.setHttpClientConfigCallback(httpClientBuilder -> {
|
||||||
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
|
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
|
||||||
return httpClientBuilder.setSSLContext(sslContext);
|
return httpClientBuilder.setSSLContext(sslContext);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true).build();
|
restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build())
|
||||||
|
.setApiCompatibilityMode(true)
|
||||||
|
.build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -106,12 +110,12 @@ public class ESConnection {
|
|||||||
String[] nameAndPwdArr = nameAndPwd.split(":");
|
String[] nameAndPwdArr = nameAndPwd.split(":");
|
||||||
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
||||||
credentialsProvider.setCredentials(AuthScope.ANY,
|
credentialsProvider.setCredentials(AuthScope.ANY,
|
||||||
new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));
|
new UsernamePasswordCredentials(nameAndPwdArr[0], nameAndPwdArr[1]));
|
||||||
restClientBuilder.setHttpClientConfigCallback(
|
restClientBuilder.setHttpClientConfigCallback(
|
||||||
httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
|
httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));
|
||||||
}
|
}
|
||||||
restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true)
|
restHighLevelClient = new RestHighLevelClientBuilder(restClientBuilder.build()).setApiCompatibilityMode(true)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
@@ -147,9 +151,9 @@ public class ESConnection {
|
|||||||
|
|
||||||
private IndexRequestBuilder indexRequestBuilder;
|
private IndexRequestBuilder indexRequestBuilder;
|
||||||
|
|
||||||
private IndexRequest indexRequest;
|
private IndexRequest indexRequest;
|
||||||
|
|
||||||
public ES8xIndexRequest(String index, String id) {
|
public ES8xIndexRequest(String index, String id){
|
||||||
indexRequest = new IndexRequest(index);
|
indexRequest = new IndexRequest(index);
|
||||||
indexRequest.id(id);
|
indexRequest.id(id);
|
||||||
|
|
||||||
@@ -190,9 +194,9 @@ public class ESConnection {
|
|||||||
|
|
||||||
private UpdateRequestBuilder updateRequestBuilder;
|
private UpdateRequestBuilder updateRequestBuilder;
|
||||||
|
|
||||||
private UpdateRequest updateRequest;
|
private UpdateRequest updateRequest;
|
||||||
|
|
||||||
public ES8xUpdateRequest(String index, String id) {
|
public ES8xUpdateRequest(String index, String id){
|
||||||
|
|
||||||
updateRequest = new UpdateRequest(index, id);
|
updateRequest = new UpdateRequest(index, id);
|
||||||
}
|
}
|
||||||
@@ -239,9 +243,9 @@ public class ESConnection {
|
|||||||
|
|
||||||
private DeleteRequestBuilder deleteRequestBuilder;
|
private DeleteRequestBuilder deleteRequestBuilder;
|
||||||
|
|
||||||
private DeleteRequest deleteRequest;
|
private DeleteRequest deleteRequest;
|
||||||
|
|
||||||
public ES8xDeleteRequest(String index, String id) {
|
public ES8xDeleteRequest(String index, String id){
|
||||||
|
|
||||||
deleteRequest = new DeleteRequest(index, id);
|
deleteRequest = new DeleteRequest(index, id);
|
||||||
|
|
||||||
@@ -268,11 +272,11 @@ public class ESConnection {
|
|||||||
|
|
||||||
private SearchRequestBuilder searchRequestBuilder;
|
private SearchRequestBuilder searchRequestBuilder;
|
||||||
|
|
||||||
private SearchRequest searchRequest;
|
private SearchRequest searchRequest;
|
||||||
|
|
||||||
private SearchSourceBuilder sourceBuilder;
|
private SearchSourceBuilder sourceBuilder;
|
||||||
|
|
||||||
public ESSearchRequest(String index) {
|
public ESSearchRequest(String index){
|
||||||
|
|
||||||
searchRequest = new SearchRequest(index);
|
searchRequest = new SearchRequest(index);
|
||||||
sourceBuilder = new SearchSourceBuilder();
|
sourceBuilder = new SearchSourceBuilder();
|
||||||
@@ -325,12 +329,10 @@ public class ESConnection {
|
|||||||
|
|
||||||
private BulkRequestBuilder bulkRequestBuilder;
|
private BulkRequestBuilder bulkRequestBuilder;
|
||||||
|
|
||||||
private BulkRequest bulkRequest;
|
private BulkRequest bulkRequest;
|
||||||
|
|
||||||
public ES8xBulkRequest() {
|
|
||||||
|
|
||||||
|
public ES8xBulkRequest(){
|
||||||
bulkRequest = new BulkRequest();
|
bulkRequest = new BulkRequest();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetBulk() {
|
public void resetBulk() {
|
||||||
@@ -398,7 +400,7 @@ public class ESConnection {
|
|||||||
|
|
||||||
private BulkResponse bulkResponse;
|
private BulkResponse bulkResponse;
|
||||||
|
|
||||||
public ES8xBulkResponse(BulkResponse bulkResponse) {
|
public ES8xBulkResponse(BulkResponse bulkResponse){
|
||||||
this.bulkResponse = bulkResponse;
|
this.bulkResponse = bulkResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,7 +440,7 @@ public class ESConnection {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return HttpHost.create(new URI(uri
|
return HttpHost.create(new URI(uri
|
||||||
.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())
|
.getScheme(), null, uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment())
|
||||||
.toString());
|
.toString());
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
throw new IllegalStateException(ex);
|
throw new IllegalStateException(ex);
|
||||||
|
|||||||
@@ -25,97 +25,98 @@ import com.google.common.collect.Lists;
|
|||||||
* 注意点:
|
* 注意点:
|
||||||
* 1. 相比于canal {@linkplain SimpleCanalConnector}, 这里get和ack操作不能有并发, 必须是一个线程执行get后,内存里执行完毕ack后再取下一个get
|
* 1. 相比于canal {@linkplain SimpleCanalConnector}, 这里get和ack操作不能有并发, 必须是一个线程执行get后,内存里执行完毕ack后再取下一个get
|
||||||
* </pre>
|
* </pre>
|
||||||
|
*
|
||||||
* todo 重复消费的概率相当高。一次批处理中,只要有一个消息处理失败,则该批次全部重试
|
* todo 重复消费的概率相当高。一次批处理中,只要有一个消息处理失败,则该批次全部重试
|
||||||
*
|
*
|
||||||
* @since 1.1.1
|
* @since 1.1.1
|
||||||
*/
|
*/
|
||||||
public class PulsarMQCanalConnector implements CanalMQConnector {
|
public class PulsarMQCanalConnector implements CanalMQConnector {
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(PulsarMQCanalConnector.class);
|
private static final Logger logger = LoggerFactory
|
||||||
|
.getLogger(PulsarMQCanalConnector.class);
|
||||||
|
|
||||||
private volatile Messages<byte[]> lastGetBatchMessage;
|
private volatile Messages<byte[]> lastGetBatchMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 连接pulsar客户端
|
* 连接pulsar客户端
|
||||||
*/
|
*/
|
||||||
private PulsarClient pulsarClient;
|
private PulsarClient pulsarClient;
|
||||||
/**
|
/**
|
||||||
* 消费者
|
* 消费者
|
||||||
*/
|
*/
|
||||||
private Consumer<byte[]> consumer;
|
private Consumer<byte[]> consumer;
|
||||||
/**
|
/**
|
||||||
* 是否扁平化Canal消息内容
|
* 是否扁平化Canal消息内容
|
||||||
*/
|
*/
|
||||||
private boolean isFlatMessage = false;
|
private boolean isFlatMessage = false;
|
||||||
/**
|
/**
|
||||||
* 主题名称
|
* 主题名称
|
||||||
*/
|
*/
|
||||||
private String topic;
|
private String topic;
|
||||||
/**
|
/**
|
||||||
* 环境连接URL
|
* 环境连接URL
|
||||||
*/
|
*/
|
||||||
private String serviceUrl;
|
private String serviceUrl;
|
||||||
/**
|
/**
|
||||||
* 角色认证token
|
* 角色认证token
|
||||||
*/
|
*/
|
||||||
private String roleToken;
|
private String roleToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* listener name
|
* listener name
|
||||||
*/
|
*/
|
||||||
private String listenerName;
|
private String listenerName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 订阅客户端名称
|
* 订阅客户端名称
|
||||||
*/
|
*/
|
||||||
private String subscriptName;
|
private String subscriptName;
|
||||||
/**
|
/**
|
||||||
* 每次批量获取数据的最大条目数,默认30
|
* 每次批量获取数据的最大条目数,默认30
|
||||||
*/
|
*/
|
||||||
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}秒时
|
||||||
* </p>
|
* </p>
|
||||||
* 任一条件满足,即执行批量消费
|
* 任一条件满足,即执行批量消费
|
||||||
*/
|
*/
|
||||||
private int getBatchTimeoutSeconds = 30;
|
private int getBatchTimeoutSeconds = 30;
|
||||||
/**
|
/**
|
||||||
* 批量处理消息时,一次批量处理的超时时间秒数
|
* 批量处理消息时,一次批量处理的超时时间秒数
|
||||||
* <p>
|
* <p>
|
||||||
* 该时间应该根据{@code batchSize}和{@code batchTimeoutSeconds}合理设置
|
* 该时间应该根据{@code batchSize}和{@code batchTimeoutSeconds}合理设置
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
private int batchProcessTimeoutSeconds = 60;
|
private int batchProcessTimeoutSeconds = 60;
|
||||||
/**
|
/**
|
||||||
* 消费失败后的重试秒数,默认60秒
|
* 消费失败后的重试秒数,默认60秒
|
||||||
*/
|
*/
|
||||||
private int redeliveryDelaySeconds = 60;
|
private int redeliveryDelaySeconds = 60;
|
||||||
/**
|
/**
|
||||||
* 当客户端接收到消息,30秒还没有返回ack给服务端时,ack超时,会重新消费该消息
|
* 当客户端接收到消息,30秒还没有返回ack给服务端时,ack超时,会重新消费该消息
|
||||||
*/
|
*/
|
||||||
private int ackTimeoutSeconds = 30;
|
private int ackTimeoutSeconds = 30;
|
||||||
/**
|
/**
|
||||||
* 是否开启消息失败重试功能,默认开启
|
* 是否开启消息失败重试功能,默认开启
|
||||||
*/
|
*/
|
||||||
private boolean isRetry = true;
|
private boolean isRetry = true;
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* true重试(-RETRY)和死信队列(-DLQ)后缀为大写,有些地方创建的为小写,需确保正确
|
* true重试(-RETRY)和死信队列(-DLQ)后缀为大写,有些地方创建的为小写,需确保正确
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
private boolean isRetryDLQUpperCase = false;
|
private boolean isRetryDLQUpperCase = false;
|
||||||
/**
|
/**
|
||||||
* 最大重试次数
|
* 最大重试次数
|
||||||
*/
|
*/
|
||||||
private int maxRedeliveryCount = 128;
|
private int maxRedeliveryCount = 128;
|
||||||
/**
|
/**
|
||||||
* 连接标识位,在连接或关闭连接后改变值
|
* 连接标识位,在连接或关闭连接后改变值
|
||||||
*/
|
*/
|
||||||
private boolean connected = false;
|
private boolean connected = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 除必要参数外,其他参数使用默认值
|
* 除必要参数外,其他参数使用默认值
|
||||||
@@ -125,21 +126,21 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param isFlatMessage true使用扁平消息
|
* @param isFlatMessage true使用扁平消息
|
||||||
* @param serviceUrl pulsar服务连接地址,通常为:pulsar:host:ip或http://host:ip
|
* @param serviceUrl pulsar服务连接地址,通常为:pulsar:host:ip或http://host:ip
|
||||||
* @param roleToken 有对应topic的消费者权限的角色token
|
* @param roleToken 有对应topic的消费者权限的角色token
|
||||||
* @param topic 订阅主题
|
* @param topic 订阅主题
|
||||||
* @param subscriptName 订阅和客户端名称,同一个订阅名视为同一个消费实例
|
* @param subscriptName 订阅和客户端名称,同一个订阅名视为同一个消费实例
|
||||||
* @date 2021/9/18 08:54
|
* @date 2021/9/18 08:54
|
||||||
* @author chad
|
* @author chad
|
||||||
* @since 1 by chad at 2021/9/18 完善
|
* @since 1 by chad at 2021/9/18 完善
|
||||||
*/
|
*/
|
||||||
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic
|
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,
|
||||||
, String subscriptName) {
|
String subscriptName){
|
||||||
this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName,null);
|
this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic
|
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,
|
||||||
, String subscriptName, String listenerName) {
|
String subscriptName, String listenerName){
|
||||||
this.isFlatMessage = isFlatMessage;
|
this.isFlatMessage = isFlatMessage;
|
||||||
this.serviceUrl = serviceUrl;
|
this.serviceUrl = serviceUrl;
|
||||||
this.roleToken = roleToken;
|
this.roleToken = roleToken;
|
||||||
@@ -158,19 +159,31 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
* @author chad
|
* @author chad
|
||||||
* @since 1 by chad at 2021/9/18 完善
|
* @since 1 by chad at 2021/9/18 完善
|
||||||
*/
|
*/
|
||||||
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic
|
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,
|
||||||
, String subscriptName, int batchSize, int getBatchTimeoutSeconds, int batchProcessTimeoutSeconds
|
String subscriptName, int batchSize, int getBatchTimeoutSeconds,
|
||||||
, int redeliveryDelaySeconds, int ackTimeoutSeconds, boolean isRetry, boolean isRetryDLQUpperCase
|
int batchProcessTimeoutSeconds, int redeliveryDelaySeconds, int ackTimeoutSeconds,
|
||||||
, int maxRedeliveryCount) {
|
boolean isRetry, boolean isRetryDLQUpperCase, int maxRedeliveryCount){
|
||||||
this(isFlatMessage, serviceUrl, roleToken, topic, subscriptName, batchSize, getBatchTimeoutSeconds
|
this(isFlatMessage,
|
||||||
, batchProcessTimeoutSeconds, redeliveryDelaySeconds, ackTimeoutSeconds, isRetry, isRetryDLQUpperCase
|
serviceUrl,
|
||||||
, maxRedeliveryCount, null);
|
roleToken,
|
||||||
|
topic,
|
||||||
|
subscriptName,
|
||||||
|
batchSize,
|
||||||
|
getBatchTimeoutSeconds,
|
||||||
|
batchProcessTimeoutSeconds,
|
||||||
|
redeliveryDelaySeconds,
|
||||||
|
ackTimeoutSeconds,
|
||||||
|
isRetry,
|
||||||
|
isRetryDLQUpperCase,
|
||||||
|
maxRedeliveryCount,
|
||||||
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic
|
public PulsarMQCanalConnector(boolean isFlatMessage, String serviceUrl, String roleToken, String topic,
|
||||||
, String subscriptName, int batchSize, int getBatchTimeoutSeconds, int batchProcessTimeoutSeconds
|
String subscriptName, int batchSize, int getBatchTimeoutSeconds,
|
||||||
, int redeliveryDelaySeconds, int ackTimeoutSeconds, boolean isRetry, boolean isRetryDLQUpperCase
|
int batchProcessTimeoutSeconds, int redeliveryDelaySeconds, int ackTimeoutSeconds,
|
||||||
, int maxRedeliveryCount, String listenerName) {
|
boolean isRetry, boolean isRetryDLQUpperCase, int maxRedeliveryCount,
|
||||||
|
String listenerName){
|
||||||
this.isFlatMessage = isFlatMessage;
|
this.isFlatMessage = isFlatMessage;
|
||||||
this.serviceUrl = serviceUrl;
|
this.serviceUrl = serviceUrl;
|
||||||
this.roleToken = roleToken;
|
this.roleToken = roleToken;
|
||||||
@@ -195,13 +208,12 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
// 连接创建客户端
|
// 连接创建客户端
|
||||||
try {
|
try {
|
||||||
ClientBuilder builder = PulsarClient.builder()
|
ClientBuilder builder = PulsarClient.builder()
|
||||||
.serviceUrl(serviceUrl)
|
.serviceUrl(serviceUrl)
|
||||||
.authentication(AuthenticationFactory.token(roleToken));
|
.authentication(AuthenticationFactory.token(roleToken));
|
||||||
if (StringUtils.isNotEmpty(listenerName)) {
|
if (StringUtils.isNotEmpty(listenerName)) {
|
||||||
builder.listenerName(listenerName);
|
builder.listenerName(listenerName);
|
||||||
}
|
}
|
||||||
pulsarClient = builder
|
pulsarClient = builder.build();
|
||||||
.build();
|
|
||||||
} catch (PulsarClientException e) {
|
} catch (PulsarClientException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -250,15 +262,14 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
builder.subscriptionType(SubscriptionType.Failover);
|
builder.subscriptionType(SubscriptionType.Failover);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
// 调用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()
|
||||||
// 最大重试次数
|
// 最大重试次数
|
||||||
.maxRedeliverCount(this.maxRedeliveryCount);
|
.maxRedeliverCount(this.maxRedeliveryCount);
|
||||||
// 指定重试队列,不是多个或通配符topic才能判断重试队列
|
// 指定重试队列,不是多个或通配符topic才能判断重试队列
|
||||||
if (!MQUtil.isPatternTag(this.topic)) {
|
if (!MQUtil.isPatternTag(this.topic)) {
|
||||||
String retryTopic = this.topic + (this.isRetryDLQUpperCase ? "-RETRY" : "-retry");
|
String retryTopic = this.topic + (this.isRetryDLQUpperCase ? "-RETRY" : "-retry");
|
||||||
@@ -267,19 +278,17 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
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());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.consumer = builder.subscribe();
|
this.consumer = builder.subscribe();
|
||||||
@@ -289,7 +298,6 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void subscribe() throws CanalClientException {
|
public void subscribe() throws CanalClientException {
|
||||||
this.subscribe(null);
|
this.subscribe(null);
|
||||||
@@ -310,7 +318,7 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
* 不关注业务执行结果,只要收到消息即认识消费成功,自动ack
|
* 不关注业务执行结果,只要收到消息即认识消费成功,自动ack
|
||||||
*
|
*
|
||||||
* @param timeout 阻塞获取消息的超时时间
|
* @param timeout 阻塞获取消息的超时时间
|
||||||
* @param unit 时间单位
|
* @param unit 时间单位
|
||||||
* @return java.util.List<com.alibaba.otter.canal.protocol.Message>
|
* @return java.util.List<com.alibaba.otter.canal.protocol.Message>
|
||||||
* @date 2021/9/13 22:24
|
* @date 2021/9/13 22:24
|
||||||
* @author chad
|
* @author chad
|
||||||
@@ -326,13 +334,14 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 关心业务执行结果,业务侧根据执行结果调用 {@link PulsarMQCanalConnector#ack()}或{@link PulsarMQCanalConnector#rollback()}
|
* 关心业务执行结果,业务侧根据执行结果调用
|
||||||
|
* {@link PulsarMQCanalConnector#ack()}或{@link PulsarMQCanalConnector#rollback()}
|
||||||
* <p>
|
* <p>
|
||||||
* 本方法示支持多线程,在MQ保障顺序的前提下,也无法提供单Topic多线程
|
* 本方法示支持多线程,在MQ保障顺序的前提下,也无法提供单Topic多线程
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param timeout 阻塞获取消息的超时时间
|
* @param timeout 阻塞获取消息的超时时间
|
||||||
* @param unit 时间单位
|
* @param unit 时间单位
|
||||||
* @return java.util.List<com.alibaba.otter.canal.protocol.Message>
|
* @return java.util.List<com.alibaba.otter.canal.protocol.Message>
|
||||||
* @date 2021/9/13 22:26
|
* @date 2021/9/13 22:26
|
||||||
* @author chad
|
* @author chad
|
||||||
@@ -366,7 +375,8 @@ public class PulsarMQCanalConnector implements CanalMQConnector {
|
|||||||
* @return java.util.List<T>
|
* @return java.util.List<T>
|
||||||
* @date 2021/9/14 15:20
|
* @date 2021/9/14 15:20
|
||||||
* @author chad
|
* @author chad
|
||||||
* @since 1 by chad at 2021/9/14 供{@link PulsarMQCanalConnector#getListWithoutAck(Long, TimeUnit)}
|
* @since 1 by chad at 2021/9/14
|
||||||
|
* 供{@link PulsarMQCanalConnector#getListWithoutAck(Long, TimeUnit)}
|
||||||
* 和{@link PulsarMQCanalConnector#getFlatListWithoutAck(Long, TimeUnit)}调用
|
* 和{@link PulsarMQCanalConnector#getFlatListWithoutAck(Long, TimeUnit)}调用
|
||||||
*/
|
*/
|
||||||
private <T> List<T> getListWithoutAck() {
|
private <T> List<T> getListWithoutAck() {
|
||||||
|
|||||||
@@ -64,6 +64,6 @@ public class PulsarMQConstants {
|
|||||||
/**
|
/**
|
||||||
* Pulsar admin服务器地址
|
* Pulsar admin服务器地址
|
||||||
*/
|
*/
|
||||||
public static final String PULSARMQ_LISTENER_NAME = ROOT + "." + "listenerName";
|
public static final String PULSARMQ_LISTENER_NAME = ROOT + "." + "listenerName";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class CanalPulsarMQConsumer implements CanalMsgConsumer {
|
|||||||
private String roleToken;
|
private String roleToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* listener name
|
* listener name
|
||||||
*/
|
*/
|
||||||
private String listenerName;
|
private String listenerName;
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class CanalPulsarMQProducer extends AbstractMQProducer implements CanalMQ
|
|||||||
builder.authentication(AuthenticationFactory.token(pulsarMQProducerConfig.getRoleToken()));
|
builder.authentication(AuthenticationFactory.token(pulsarMQProducerConfig.getRoleToken()));
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getListenerName())) {
|
if (StringUtils.isNotEmpty(pulsarMQProducerConfig.getListenerName())) {
|
||||||
//listener name
|
// listener name
|
||||||
builder.listenerName(pulsarMQProducerConfig.getListenerName());
|
builder.listenerName(pulsarMQProducerConfig.getListenerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package com.taobao.tddl.dbsync.binlog;
|
package com.taobao.tddl.dbsync.binlog;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.*;
|
||||||
|
|
||||||
import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.appendNumber2;
|
import java.nio.charset.Charset;
|
||||||
import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.appendNumber4;
|
|
||||||
import static com.taobao.tddl.dbsync.binlog.event.RowsLogBuffer.usecondsToStr;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理下MySQL json二进制转化为可读的字符串
|
* 处理下MySQL json二进制转化为可读的字符串
|
||||||
@@ -34,26 +32,25 @@ public class JsonConversion {
|
|||||||
public static final char JSONB_FALSE_LITERAL = '\2';
|
public static final char JSONB_FALSE_LITERAL = '\2';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The size of offset or size fields in the small and the large storage
|
* The size of offset or size fields in the small and the large storage format
|
||||||
* format for JSON objects and JSON arrays.
|
* for JSON objects and JSON arrays.
|
||||||
*/
|
*/
|
||||||
public static final int SMALL_OFFSET_SIZE = 2;
|
public static final int SMALL_OFFSET_SIZE = 2;
|
||||||
public static final int LARGE_OFFSET_SIZE = 4;
|
public static final int LARGE_OFFSET_SIZE = 4;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The size of key entries for objects when using the small storage format
|
* The size of key entries for objects when using the small storage format or
|
||||||
* or the large storage format. In the small format it is 4 bytes (2 bytes
|
* the large storage format. In the small format it is 4 bytes (2 bytes for key
|
||||||
* for key length and 2 bytes for key offset). In the large format it is 6
|
* length and 2 bytes for key offset). In the large format it is 6 (2 bytes for
|
||||||
* (2 bytes for length, 4 bytes for offset).
|
* length, 4 bytes for offset).
|
||||||
*/
|
*/
|
||||||
public static final int KEY_ENTRY_SIZE_SMALL = (2 + SMALL_OFFSET_SIZE);
|
public static final int KEY_ENTRY_SIZE_SMALL = (2 + SMALL_OFFSET_SIZE);
|
||||||
public static final int KEY_ENTRY_SIZE_LARGE = (2 + LARGE_OFFSET_SIZE);
|
public static final int KEY_ENTRY_SIZE_LARGE = (2 + LARGE_OFFSET_SIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The size of value entries for objects or arrays. When using the small
|
* The size of value entries for objects or arrays. When using the small storage
|
||||||
* storage format, the entry size is 3 (1 byte for type, 2 bytes for
|
* format, the entry size is 3 (1 byte for type, 2 bytes for offset). When using
|
||||||
* offset). When using the large storage format, it is 5 (1 byte for type, 4
|
* the large storage format, it is 5 (1 byte for type, 4 bytes for offset).
|
||||||
* bytes for offset).
|
|
||||||
*/
|
*/
|
||||||
public static final int VALUE_ENTRY_SIZE_SMALL = (1 + SMALL_OFFSET_SIZE);
|
public static final int VALUE_ENTRY_SIZE_SMALL = (1 + SMALL_OFFSET_SIZE);
|
||||||
public static final int VALUE_ENTRY_SIZE_LARGE = (1 + LARGE_OFFSET_SIZE);
|
public static final int VALUE_ENTRY_SIZE_LARGE = (1 + LARGE_OFFSET_SIZE);
|
||||||
@@ -160,13 +157,12 @@ public class JsonConversion {
|
|||||||
if (len < n + str_len) {
|
if (len < n + str_len) {
|
||||||
throw new IllegalArgumentException("illegal json data");
|
throw new IllegalArgumentException("illegal json data");
|
||||||
}
|
}
|
||||||
return new Json_Value(Json_enum_type.STRING, buffer.rewind()
|
return new Json_Value(Json_enum_type.STRING,
|
||||||
.forward((int) n)
|
buffer.rewind().forward((int) n).getFixString((int) str_len, charset));
|
||||||
.getFixString((int) str_len, charset));
|
|
||||||
case JSONB_TYPE_OPAQUE:
|
case JSONB_TYPE_OPAQUE:
|
||||||
/*
|
/*
|
||||||
* There should always be at least one byte, which tells the
|
* There should always be at least one byte, which tells the field type of the
|
||||||
* field type of the opaque value.
|
* opaque value.
|
||||||
*/
|
*/
|
||||||
// The type is encoded as a uint8 that maps to an
|
// The type is encoded as a uint8 that maps to an
|
||||||
// enum_field_types.
|
// enum_field_types.
|
||||||
@@ -368,45 +364,45 @@ public class JsonConversion {
|
|||||||
buf.append('"').append(text).append('"');
|
buf.append('"').append(text).append('"');
|
||||||
} else if (m_field_type == LogEvent.MYSQL_TYPE_DATE || m_field_type == LogEvent.MYSQL_TYPE_DATETIME
|
} else if (m_field_type == LogEvent.MYSQL_TYPE_DATE || m_field_type == LogEvent.MYSQL_TYPE_DATETIME
|
||||||
|| m_field_type == LogEvent.MYSQL_TYPE_TIMESTAMP) {
|
|| m_field_type == LogEvent.MYSQL_TYPE_TIMESTAMP) {
|
||||||
long packed_value = m_data.getLong64();
|
long packed_value = m_data.getLong64();
|
||||||
if (packed_value == 0) {
|
if (packed_value == 0) {
|
||||||
text = "0000-00-00 00:00:00";
|
text = "0000-00-00 00:00:00";
|
||||||
} else {
|
} else {
|
||||||
// 构造TimeStamp只处理到秒
|
// 构造TimeStamp只处理到秒
|
||||||
long ultime = Math.abs(packed_value);
|
long ultime = Math.abs(packed_value);
|
||||||
long intpart = ultime >> 24;
|
long intpart = ultime >> 24;
|
||||||
int frac = (int) (ultime % (1L << 24));
|
int frac = (int) (ultime % (1L << 24));
|
||||||
long ymd = intpart >> 17;
|
long ymd = intpart >> 17;
|
||||||
long ym = ymd >> 5;
|
long ym = ymd >> 5;
|
||||||
long hms = intpart % (1 << 17);
|
long hms = intpart % (1 << 17);
|
||||||
// text =
|
// text =
|
||||||
// String.format("%04d-%02d-%02d %02d:%02d:%02d",
|
// String.format("%04d-%02d-%02d %02d:%02d:%02d",
|
||||||
// (int) (ym / 13),
|
// (int) (ym / 13),
|
||||||
// (int) (ym % 13),
|
// (int) (ym % 13),
|
||||||
// (int) (ymd % (1 << 5)),
|
// (int) (ymd % (1 << 5)),
|
||||||
// (int) (hms >> 12),
|
// (int) (hms >> 12),
|
||||||
// (int) ((hms >> 6) % (1 << 6)),
|
// (int) ((hms >> 6) % (1 << 6)),
|
||||||
// (int) (hms % (1 << 6)));
|
// (int) (hms % (1 << 6)));
|
||||||
StringBuilder builder = new StringBuilder(26);
|
StringBuilder builder = new StringBuilder(26);
|
||||||
appendNumber4(builder, (int) (ym / 13));
|
appendNumber4(builder, (int) (ym / 13));
|
||||||
builder.append('-');
|
builder.append('-');
|
||||||
appendNumber2(builder, (int) (ym % 13));
|
appendNumber2(builder, (int) (ym % 13));
|
||||||
builder.append('-');
|
builder.append('-');
|
||||||
appendNumber2(builder, (int) (ymd % (1 << 5)));
|
appendNumber2(builder, (int) (ymd % (1 << 5)));
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
appendNumber2(builder, (int) (hms >> 12));
|
appendNumber2(builder, (int) (hms >> 12));
|
||||||
builder.append(':');
|
builder.append(':');
|
||||||
appendNumber2(builder, (int) ((hms >> 6) % (1 << 6)));
|
appendNumber2(builder, (int) ((hms >> 6) % (1 << 6)));
|
||||||
builder.append(':');
|
builder.append(':');
|
||||||
appendNumber2(builder, (int) (hms % (1 << 6)));
|
appendNumber2(builder, (int) (hms % (1 << 6)));
|
||||||
builder.append('.').append(usecondsToStr(frac, 6));
|
builder.append('.').append(usecondsToStr(frac, 6));
|
||||||
text = builder.toString();
|
text = builder.toString();
|
||||||
}
|
}
|
||||||
buf.append('"').append(text).append('"');
|
buf.append('"').append(text).append('"');
|
||||||
} else {
|
} else {
|
||||||
text = m_data.getFixString((int) m_length, charset);
|
text = m_data.getFixString((int) m_length, charset);
|
||||||
buf.append('"').append(escapse(text)).append('"');
|
buf.append('"').append(escapse(text)).append('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case STRING:
|
||||||
@@ -452,7 +448,8 @@ public class JsonConversion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static enum Json_enum_type {
|
public static enum Json_enum_type {
|
||||||
OBJECT, ARRAY, STRING, INT, UINT, DOUBLE, LITERAL_NULL, LITERAL_TRUE, LITERAL_FALSE, OPAQUE, ERROR
|
OBJECT, ARRAY, STRING, INT, UINT, DOUBLE, LITERAL_NULL, LITERAL_TRUE,
|
||||||
|
LITERAL_FALSE, OPAQUE, ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.taobao.tddl.dbsync.binlog;
|
package com.taobao.tddl.dbsync.binlog;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -9,8 +11,6 @@ import org.junit.rules.Timeout;
|
|||||||
import com.taobao.tddl.dbsync.binlog.JsonConversion.Json_Value;
|
import com.taobao.tddl.dbsync.binlog.JsonConversion.Json_Value;
|
||||||
import com.taobao.tddl.dbsync.binlog.JsonConversion.Json_enum_type;
|
import com.taobao.tddl.dbsync.binlog.JsonConversion.Json_enum_type;
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
public class JsonConversion_Json_ValueTest {
|
public class JsonConversion_Json_ValueTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
@@ -50,7 +50,6 @@ public class JsonConversion_Json_ValueTest {
|
|||||||
// Act
|
// Act
|
||||||
thrown.expect(IllegalArgumentException.class);
|
thrown.expect(IllegalArgumentException.class);
|
||||||
JsonConversion.parse_value(type, buffer, len, charsetName);
|
JsonConversion.parse_value(type, buffer, len, charsetName);
|
||||||
|
|
||||||
// Method is not expected to return due to exception thrown
|
// Method is not expected to return due to exception thrown
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +59,10 @@ public class JsonConversion_Json_ValueTest {
|
|||||||
|
|
||||||
// {"internal_uri_rewrite": {"(.*)(/[^/]+\\.(mp|MP)4)$": "$1/mp4$2"}}
|
// {"internal_uri_rewrite": {"(.*)(/[^/]+\\.(mp|MP)4)$": "$1/mp4$2"}}
|
||||||
String jsonData = "{\"internal_uri_rewrite\": {\"(.*)(/[^/]+\\\\.(mp|MP)4)$\": \"$1/mp4$2\"}}";
|
String jsonData = "{\"internal_uri_rewrite\": {\"(.*)(/[^/]+\\\\.(mp|MP)4)$\": \"$1/mp4$2\"}}";
|
||||||
byte[] data = new byte[]{1, 0, 74, 0, 11, 0, 20, 0, 0, 31, 0, 105, 110, 116, 101, 114, 110, 97, 108, 95, 117, 114, 105, 95, 114, 101, 119, 114, 105, 116, 101, 1, 0, 43, 0, 11, 0, 23, 0, 12, 34, 0, 40, 46, 42, 41, 40, 47, 91, 94, 47, 93, 43, 92, 46, 40, 109, 112, 124, 77, 80, 41, 52, 41, 36, 8, 36, 49, 47, 109, 112, 52, 36, 50};
|
byte[] data = new byte[] { 1, 0, 74, 0, 11, 0, 20, 0, 0, 31, 0, 105, 110, 116, 101, 114, 110, 97, 108, 95, 117,
|
||||||
|
114, 105, 95, 114, 101, 119, 114, 105, 116, 101, 1, 0, 43, 0, 11, 0, 23, 0, 12, 34,
|
||||||
|
0, 40, 46, 42, 41, 40, 47, 91, 94, 47, 93, 43, 92, 46, 40, 109, 112, 124, 77, 80, 41,
|
||||||
|
52, 41, 36, 8, 36, 49, 47, 109, 112, 52, 36, 50 };
|
||||||
final LogBuffer buffer = new LogBuffer(data, 0, 74);
|
final LogBuffer buffer = new LogBuffer(data, 0, 74);
|
||||||
|
|
||||||
Charset charset = Charset.forName("UTF-8");
|
Charset charset = Charset.forName("UTF-8");
|
||||||
@@ -68,7 +70,6 @@ public class JsonConversion_Json_ValueTest {
|
|||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
jsonValue.toJsonString(builder, charset);
|
jsonValue.toJsonString(builder, charset);
|
||||||
|
|
||||||
|
|
||||||
Assert.assertEquals(builder.toString(), jsonData);
|
Assert.assertEquals(builder.toString(), jsonData);
|
||||||
|
|
||||||
Assert.assertEquals(jsonValue.key(0, charset), "internal_uri_rewrite");
|
Assert.assertEquals(jsonValue.key(0, charset), "internal_uri_rewrite");
|
||||||
|
|||||||
Reference in New Issue
Block a user